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
- Verify the file is actually a video: run `ffprobe -v error -show_streams <path>` yourself and check the stream list
- If the asset is audio-only, re-export or replace it with a video overlay (e.g. an alpha-capable .webm/.mov)
- 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`
- 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
- Verify asset type before feeding it to the pipeline (extension + ffprobe)
- Map/strip extra streams (cover art) when muxing assets
- Validate downloads (size, ffprobe success) before registering them as assets
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
- output width and height must be positive
- source fps must be finite and positive; provide --fps
- variable or ambiguous frame rate
- analyze() needs at least one frame
- analyze() needs at least one frame
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)