{"record":{"id":"62df5c8501e80e3a","repo":"sgl-project/sglang","slug":"could-not-decode-video-e","errorCode":null,"errorMessage":"Could not decode video: {e}","messagePattern":"Could not decode video: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/utils/common.py","lineNumber":1979,"sourceCode":"    if isinstance(video_file, VideoData):\n        # preprocess_kwargs is consumed by the multimodal processor, not here.\n        video_file = video_file.url\n\n    if isinstance(video_file, (list, tuple, torch.Tensor, np.ndarray)):\n        return video_file\n\n    source = _normalize_video_input(video_file)\n    if source is None:\n        raise ValueError(f\"Unsupported video input type: {type(video_file)}\")\n\n    device = \"cuda\" if use_gpu else \"cpu\"\n    try:\n        return VideoDecoderWrapper(source, device=device)\n    except (ImportError, MemoryError):\n        raise  # missing backend / OOM is not a bad payload\n    except Exception as e:\n        # Broad on purpose: torchcodec raises RuntimeError, decord its own type.\n        raise ValueError(f\"Could not decode video: {e}\") from e\n\n\ndef sample_video_frames(video, *, desired_fps: int, max_frames: int) -> list[int]:\n    total_frames = len(video)\n    assert total_frames > 0, \"Video must have at least one frame\"\n\n    avg_fps = video.avg_fps\n    duration = total_frames / avg_fps if avg_fps > 0 else 0\n    fps = min(desired_fps, avg_fps)\n\n    num_frames = math.floor(duration * fps)\n    num_frames = min(max_frames, num_frames, total_frames)\n    num_frames = max(1, num_frames)  # At least one frame\n    if num_frames == total_frames:\n        return list(range(total_frames))\n    else:\n        return np.linspace(0, total_frames - 1, num_frames, dtype=int).tolist()\n","sourceCodeStart":1961,"sourceCodeEnd":1997,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/utils/common.py#L1961-L1997","documentation":"The video decoder wrapper (torchcodec or decord) raised an unexpected exception while opening/decoding the video source; it is rewrapped as ValueError because backends raise heterogeneous exception types (RuntimeError etc.). The chained 'from e' preserves the root cause.","triggerScenarios":"Corrupt/truncated video file, unsupported codec/container, unreadable URL, or backend inconsistency — any non-ImportError/MemoryError from VideoDecoderWrapper construction.","commonSituations":"Users uploading broken or unusual-codec videos; partially downloaded files; decord/torchcodec version incompatibilities with certain codecs.","solutions":["Inspect the chained original exception (__cause__) for the true backend error","Verify the video opens with ffprobe or an external player; re-encode to H.264 MP4 if codec is exotic","Ensure torchcodec/decord and ffmpeg are installed and versions are compatible","Handle at the request layer and reject/report the bad payload instead of crashing the server"],"exampleFix":"// before\nvideo = load_video(path)  # crashes on corrupt file\n// after\ntry:\n    video = load_video(path)\nexcept ValueError as e:\n    raise HTTPException(400, f\"bad video: {e}\") from e","handlingStrategy":"try-catch","validationCode":"import subprocess\nsubprocess.run([\"ffprobe\", \"-v\", \"error\", path], check=True)  # cheap pre-check","typeGuard":null,"tryCatchPattern":"try:\n    video = load_video(path)\nexcept ValueError as e:\n    if \"Could not decode\" in str(e):\n        reject_payload(original=e.__cause__)","preventionTips":["Re-encode user uploads to H.264 MP4 before inference","Always inspect e.__cause__ for the torchcodec/decord root error","Install matching torchcodec + ffmpeg versions"],"tags":["video","codec","decode","torchcodec","decord"],"backgroundTag":"media-decode-failure","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}