affaan-m/ECC · error · ValueError

asset must contain a video stream

Error message

asset must contain a video stream: {path}

What it means

probe_asset runs ffprobe on an asset and requires exactly one video stream; it raises ValueError('asset must contain a video stream: {path}') when ffprobe returns zero streams or more than one. Zero usually means the file has no video track; multiple streams means the probe filter was ambiguous and the tool refuses to guess.

Solutions

  1. Verify the file is actually a video: run `ffprobe -v error -show_streams <path>` yourself and check the stream list
  2. If the asset is audio-only, re-export or replace it with a video overlay (e.g. an alpha-capable .webm/.mov)
  3. If there are two video streams (e.g. cover-art + video), strip the extra stream: `ffmpeg -i in.mkv -map 0:v:0 -c copy out.mkv`
  4. If the file is corrupted, re-download/re-encode it and confirm one video stream before retrying

Example fix

# before
info = resolve.probe_asset('narration.mp3')  # audio only
# after
info = resolve.probe_asset('overlay_animation.webm')  # single video stream
Defensive patterns

Strategy: validation

Validate before calling

import json, subprocess

def has_single_video_stream(path):
    r = subprocess.run(['ffprobe', '-v', 'error', '-show_streams', '-of', 'json', str(path)],
                       capture_output=True, text=True)
    streams = json.loads(r.stdout).get('streams', [])
    return len(streams) == 1

assert has_single_video_stream('overlay.webm')

Try / catch

try:
    info = resolve.probe_asset(path)
except ValueError as e:
    if 'must contain a video stream' in str(e):
        raise AssetError(f'{path} is not a single-stream video') from e
    raise

Prevention

When it happens

Trigger: Probing an audio-only file (mp3, wav), a subtitle/srt file, a corrupted download, or an asset where ffprobe's stream selection yields several video streams (e.g. multiple video tracks or unusual container layouts).

Common situations: Wrong file passed as overlay asset (audio narration instead of animation); a .webm with attached cover art adding a second (mjpeg) stream; truncated or zero-byte file that ffprobe can't parse.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/36d25dcfb82af66d. Report an issue: GitHub.

Appendix: source

Thrown at skills/taste-application/scripts/tasteforge/resolve.py:62

            "-v",
            "error",
            "-select_streams",
            "v:0",
            "-count_frames",
            "-show_entries",
            "stream=avg_frame_rate,r_frame_rate,nb_read_frames,pix_fmt",
            "-of",
            "json",
            str(path),
        ],
        capture_output=True,
        text=True,
        check=True,
        timeout=120,
    )
    streams = json.loads(result.stdout).get("streams", [])
    if len(streams) != 1:
        raise ValueError(f"asset must contain a video stream: {path}")
    stream = streams[0]
    average = _fps(stream["avg_frame_rate"])
    if average != _fps(stream["r_frame_rate"]):
        raise ValueError(f"variable or ambiguous frame rate: {path}")
    pixel_format = stream.get("pix_fmt", "")
    alpha = pixel_format.startswith(("yuva", "gbrap")) or pixel_format in {
        "rgba",
        "bgra",
        "argb",
        "abgr",
        "rgba64be",
        "rgba64le",
        "bgra64be",
        "bgra64le",
        "ya8",
        "ya16be",
        "ya16le",
    }

View on GitHub (pinned to 8321021c54)