sgl-project/sglang · error · ValueError

Could not decode video: {e}

Error message

Could not decode video: {e}

What it means

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.

Source

Thrown at python/sglang/srt/utils/common.py:1979

    if isinstance(video_file, VideoData):
        # preprocess_kwargs is consumed by the multimodal processor, not here.
        video_file = video_file.url

    if isinstance(video_file, (list, tuple, torch.Tensor, np.ndarray)):
        return video_file

    source = _normalize_video_input(video_file)
    if source is None:
        raise ValueError(f"Unsupported video input type: {type(video_file)}")

    device = "cuda" if use_gpu else "cpu"
    try:
        return VideoDecoderWrapper(source, device=device)
    except (ImportError, MemoryError):
        raise  # missing backend / OOM is not a bad payload
    except Exception as e:
        # Broad on purpose: torchcodec raises RuntimeError, decord its own type.
        raise ValueError(f"Could not decode video: {e}") from e


def sample_video_frames(video, *, desired_fps: int, max_frames: int) -> list[int]:
    total_frames = len(video)
    assert total_frames > 0, "Video must have at least one frame"

    avg_fps = video.avg_fps
    duration = total_frames / avg_fps if avg_fps > 0 else 0
    fps = min(desired_fps, avg_fps)

    num_frames = math.floor(duration * fps)
    num_frames = min(max_frames, num_frames, total_frames)
    num_frames = max(1, num_frames)  # At least one frame
    if num_frames == total_frames:
        return list(range(total_frames))
    else:
        return np.linspace(0, total_frames - 1, num_frames, dtype=int).tolist()

View on GitHub (pinned to 0132848349)

Solutions

  1. Inspect the chained original exception (__cause__) for the true backend error
  2. Verify the video opens with ffprobe or an external player; re-encode to H.264 MP4 if codec is exotic
  3. Ensure torchcodec/decord and ffmpeg are installed and versions are compatible
  4. Handle at the request layer and reject/report the bad payload instead of crashing the server

Example fix

// before
video = load_video(path)  # crashes on corrupt file
// after
try:
    video = load_video(path)
except ValueError as e:
    raise HTTPException(400, f"bad video: {e}") from e
Defensive patterns

Strategy: try-catch

Validate before calling

import subprocess
subprocess.run(["ffprobe", "-v", "error", path], check=True)  # cheap pre-check

Try / catch

try:
    video = load_video(path)
except ValueError as e:
    if "Could not decode" in str(e):
        reject_payload(original=e.__cause__)

Prevention

When it happens

Trigger: Corrupt/truncated video file, unsupported codec/container, unreadable URL, or backend inconsistency — any non-ImportError/MemoryError from VideoDecoderWrapper construction.

Common situations: Users uploading broken or unusual-codec videos; partially downloaded files; decord/torchcodec version incompatibilities with certain codecs.

Related errors


AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28). Data as JSON: /api/errors/62df5c8501e80e3a. Report an issue: GitHub.