{"record":{"id":"0ac95f661c850f7b","repo":"unslothai/unsloth","slug":"webm-export-failed-the-clip-has-no-video-stream","errorCode":null,"errorMessage":"WebM export failed: the clip has no video stream.","messagePattern":"WebM export failed: the clip has no video stream\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":501,"severity":"error","filePath":"studio/backend/core/inference/video_gallery.py","lineNumber":143,"sourceCode":"    dest = transcode_to_file(video_id, fmt)\n    if dest is None:\n        return None\n    try:\n        return dest.read_bytes()\n    finally:\n        dest.unlink(missing_ok = True)\n\n\ndef _transcode_webm(path: Path, dest: Path) -> None:\n    \"\"\"Transcode ``path`` to VP9 (+ Opus when the clip has audio) at ``dest``.\"\"\"\n    try:\n        import av\n    except Exception as exc:  # noqa: BLE001 -- no PyAV -> no transcode\n        raise RuntimeError(\"WebM export needs the 'av' package (PyAV).\") from exc\n    try:\n        with av.open(str(path)) as src, av.open(str(dest), \"w\", format = \"webm\") as dst:\n            if not src.streams.video:\n                raise RuntimeError(\"WebM export failed: the clip has no video stream.\")\n            in_v = src.streams.video[0]\n            rate = in_v.average_rate or 24\n            out_v = dst.add_stream(\"libvpx-vp9\", rate = rate)\n            out_v.width = in_v.codec_context.width\n            out_v.height = in_v.codec_context.height\n            out_v.pix_fmt = \"yuv420p\"\n            # Realtime settings: VP9's default \"good\" profile is slow; cpu-used 8 + row-mt is much faster at a small quality cost.\n            out_v.options = {\"deadline\": \"realtime\", \"cpu-used\": \"8\", \"row-mt\": \"1\"}\n            # An LTX-2 clip carries a synchronized audio track and WebM is the web-embed format, so dropping it would hand back half the\n            # result. Opus is WebM's audio codec: resample to its 48 kHz grid and feed whole frames through a FIFO (960 samples per frame).\n            in_a = src.streams.audio[0] if src.streams.audio else None\n            out_a = fifo = resampler = None\n            if in_a is not None:\n                try:\n                    stereo = (getattr(in_a.codec_context.layout, \"nb_channels\", 1) or 1) > 1\n                    layout = \"stereo\" if stereo else \"mono\"\n                    out_a = dst.add_stream(\"libopus\", rate = 48000, layout = layout)\n                    resampler = av.audio.resampler.AudioResampler(","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/inference/video_gallery.py#L125-L161","documentation":"Raised inside _transcode_webm right after opening the source clip when src.streams.video is empty, meaning the container opened but contains no video stream at all. It is a distinct, deliberate check before any encoder work so a bad input is not misreported as an encoder problem.","triggerScenarios":"Exporting to WebM a file that is audio-only or a still-image container; a truncated/corrupt clip whose video track is unparseable so PyAV reports no video streams; passing a file with only a cover-art stream.","commonSituations":"Pipeline bug upstream wrote an empty or audio-only file where a video was expected; user-uploaded file with the wrong extension (.mp4 that is really an audio file).","solutions":["Inspect the source file: ffprobe input.mp4 (or av.open + src.streams) to confirm it has a video stream.","Fix or re-generate the source clip so it actually contains video frames.","If the file is valid elsewhere, check for codec support in the installed PyAV build."],"exampleFix":"# before\n_transcode_webm(Path(\"audio_only.mp4\"), dest)  # RuntimeError\n\n# after: verify the source has a video track first\nimport av\nwith av.open(str(src_path)) as c:\n    assert c.streams.video, \"source has no video stream\"","handlingStrategy":"validation","validationCode":"import av\n\ndef has_video_stream(path) -> bool:\n    with av.open(str(path)) as c:\n        return bool(c.streams.video)","typeGuard":null,"tryCatchPattern":"try:\n    _transcode_webm(src, dest)\nexcept RuntimeError as e:\n    if \"no video stream\" in str(e):\n        reject_source_clip()  # input defect; do not retry, re-encode or regenerate\n    else:\n        raise","preventionTips":["Verify src.streams.video immediately after av.open on any file you produce.","Treat 'opened but no video stream' as upstream corruption, not a settings issue.","Log the file's ffprobe output when this fires."],"tags":["video","webm","corrupt-file","validation"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}