{"record":{"id":"43a9dab46119281d","repo":"invoke-ai/InvokeAI","slug":"unable-to-open-video-decoder-output-stream","errorCode":null,"errorMessage":"Unable to open video decoder output stream","messagePattern":"Unable to open video decoder output stream","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"invokeai/app/util/video_thumbnails.py","lineNumber":244,"sourceCode":"    is_canceled: Optional[Callable[[], bool]] = None,\n    first_frame_timeout: Optional[float] = None,\n) -> Iterator[np.ndarray]:\n    \"\"\"Streams decoded frames from an isolated worker with bounded memory and wait time.\n\n    ``timeout`` bounds decoder *inactivity*: it is restarted after every frame, so a long\n    video is not killed for being long. ``first_frame_timeout`` overrides that budget for\n    the first frame only, letting a caller that already spent part of the budget waiting\n    for capacity charge that wait against the same deadline instead of granting a fresh one.\n    \"\"\"\n    proc = _spawn_worker(\n        \"stream\",\n        str(video_path),\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n    )\n    if proc.stdout is None or proc.stderr is None:\n        _terminate_process_tree(proc)\n        raise RuntimeError(\"Unable to open video decoder output stream\")\n    memory_monitor_stop, _memory_exceeded, memory_monitor = _start_worker_memory_monitor(proc)\n\n    results: queue.Queue[tuple[str, object]] = queue.Queue(maxsize=1)\n    stopped = threading.Event()\n    stderr_tail = bytearray()\n\n    def read_stderr() -> str:\n        return bytes(stderr_tail).decode(errors=\"replace\").strip()\n\n    def drain_stderr() -> None:\n        while chunk := proc.stderr.read(4096):\n            stderr_tail.extend(chunk)\n            if len(stderr_tail) > MAX_DECODE_STDERR_BYTES:\n                del stderr_tail[:-MAX_DECODE_STDERR_BYTES]\n\n    def read_exactly(size: int) -> bytes:\n        chunks: list[bytes] = []\n        remaining = size","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/util/video_thumbnails.py#L226-L262","documentation":"Raised when the spawned ffmpeg/worker process used for streamed frame iteration was created but its stdout or stderr pipe is None, meaning the output streams could not be opened. This is essentially an OS-level pipe-creation/resource failure or an invalid Popen configuration. The worker process tree is terminated before raising to avoid leaking processes.","triggerScenarios":"subprocess.Popen returning a process whose stdout/stderr is None despite stdout=subprocess.PIPE — practically only when pipes fail to allocate (fd exhaustion, ulimit -n too low), or if the Popen call was modified to not use PIPE.","commonSituations":"Servers with very low file-descriptor limits running many concurrent video jobs; containers with small RLIMIT_NOFILE; a fd leak elsewhere in the app exhausting descriptors.","solutions":["Raise the file-descriptor limit (ulimit -n / container RLIMIT_NOFILE, e.g. 65536) and retry.","Check for fd leaks in the application (lsof | wc -l) — leaked pipes from previous jobs will exhaust the limit.","Reduce concurrency of iter_video_frames calls so fewer simultaneous pipes are open.","If the error persists on a stock install, report it — with the library's own Popen config this should be unreachable."],"exampleFix":"// before\nfor frame in iter_video_frames(path): ...  # RuntimeError: Unable to open video decoder output stream\n// after\nimport resource\nresource.setrlimit(resource.RLIMIT_NOFILE, (65536, 65536))  # in service startup\nfor frame in iter_video_frames(path): ...","handlingStrategy":"retry","validationCode":"# check fd headroom before heavy video work\nimport os, resource\nsoft, _ = resource.getrlimit(resource.RLIMIT_NOFILE)\nassert soft > 1024, f\"fd limit too low: {soft}\"","typeGuard":null,"tryCatchPattern":"try:\n    for frame in iter_video_frames(path):\n        ...\nexcept RuntimeError as e:\n    if \"output stream\" in str(e):\n        raise FdExhaustionError(\"raise RLIMIT_NOFILE and retry\") from e","preventionTips":["Raise RLIMIT_NOFILE in containers (e.g. 65536)","Audit for fd leaks (open pipes/sockets) app-wide","Cap concurrent iter_video_frames users","Re-run the job after load drops; this error is usually transient"],"tags":["video","subprocess","file-descriptors","resources"],"backgroundTag":"pipe-open-failed","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}