Skip to content

[Bug]: ffmpeg processes leak when a session fails to start (and via DELETE /api/channels/:id/sessions) — accumulating orphans starve all new streams #1950

Description

@dbdmdbdmdbdm

This issue respects the following points:

Description of the bug

When an HLS session fails to start (e.g. under CPU load: Stream not ready yet. RetryError starting stream after retrying → session shutdown), the ffmpeg process that was spawned for it is not killed. It keeps running to its full -t duration (which can be hours for a movie), writing segments into the channel's stream directory with no session tracking it.

This causes a death spiral on modest hardware:

  1. A tune fails under load → orphan ffmpeg left running, eating CPU.
  2. The client retries (or the user zaps back) → next attempt is even more starved → fails → another orphan.
  3. Repeat until the box is saturated. We observed 11 ffmpeg processes vs. 4 tracked sessions on a 4-core N100 (load average 26), including one orphan that had been running for ~5 hours with no corresponding entry in /api/sessions at all. At that point every new tune fails (No master playlist found ...) while already-established streams keep playing — which looks to users like "random channels are broken."

Two related observations:

  • DELETE /api/channels/:id/sessions also leaks the ffmpeg. It returns 201 and removes the session record, but the ffmpeg process survives (verified: still running 10+ seconds later, runs to its -t duration). So the session-stop API cannot be used to clean up — it creates orphans.
  • Natural idle reaping works correctly: when a client disconnects cleanly, both the session and its ffmpeg are gone within ~150s. The leak is specific to the failed-start and explicit-delete paths.

Diagnostic signature for anyone else hitting this: pgrep -cx ffmpeg much greater than the number of channels in GET /api/sessions = orphaned transcodes.

Reproduction steps

  1. Run Tunarr (Docker) on modest hardware (4-core Intel N100, VAAPI transcode) with channels that require transcoding.
  2. Tune several channels in quick succession (channel zapping from an HLS client), or concurrently tune 2-3 heavy channels, until a session start fails with Stream not ready yet. Retry.
  3. Watch ps -C ffmpeg vs GET /api/sessions.
  4. Alternatively: start a stream, then call DELETE /api/channels/:id/sessions and watch the ffmpeg process survive.

What is the current bug behavior?

ffmpeg processes from failed session starts (and from DELETE /api/channels/:id/sessions) are never reaped. They accumulate, consume CPU for hours, and starve all subsequent session starts while the API stays healthy (200), so external health checks don't catch it.

What is the expected correct behavior?

When a session fails to start or is deleted via the API, the associated ffmpeg process should be killed (the same cleanup that already runs correctly on idle disconnect).

Tunarr version

Latest (1.3.8, Docker ghcr.io/chrisbenincasa/tunarr:latest)

FFMPEG encoder type

VAAPI

Deployment Type

Docker

What operating system are you using?

Debian 13 (LXC on Proxmox), Intel N100

Full server logs

2026-07-11T21:56:48.747Z [info]: channel-80-transcode still running after SIGTERM. Sending SIGKILL
2026-07-11T21:56:50.010Z [info]: channel-80-transcode exited. (signal=SIGKILL, code=-1, expected?=true)
2026-07-11T21:57:05.069Z [error]: Error starting stream after retrying {"sessionId":"e57e4dfd-bead-4d9c-9f75-af37e281e1d9","channel":"d6abfeea-...","sessionType":"hls"}
    err: { "message": "Stream not ready yet. Retry",
          at retries (/snapshot/dist/bundle.cjs:1390:4662)
          at async mse.waitForStreamReady (/snapshot/dist/bundle.cjs:1390:3774) }
2026-07-11T21:57:05.085Z [error]: Received error from session. Shutting down {"sessionId":"80779740-..._hls"}
2026-07-11T21:57:05.115Z [error]: No master playlist found for channel 80779740-... at path /config/tunarr/streams/stream_80779740-.../playlist.m3u8. This could mean the stream is not ready.

After these log lines, three ffmpeg processes for channel 80779740-... were still alive (ps showed them running; the oldest orphan on the box had etimes ≈ 17,500s with no session). A docker restart tunarr was the only built-in way to recover.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions