affaan-m/ECC · error · ValueError
variable or ambiguous frame rate
Error message
variable or ambiguous frame rate: {path} What it means
After probing, probe_asset compares the stream's avg_frame_rate with r_frame_rate; it raises ValueError('variable or ambiguous frame rate: {path}') when they differ or either cannot be normalized to the same fps. This guards compositing math that assumes a constant frame rate — VFR input would desynchronize placements.
Solutions
- Re-encode the asset to constant frame rate matching the timeline: `ffmpeg -i in.mp4 -vf fps=30 -vsync cfr out.mp4`
- Or run `ffmpeg -i in.mp4 -enc_q -vsync cfr -r 30 out.mp4` to force CFR without re-filtering
- Use source footage recorded at constant frame rate (set OBS to CFR) instead of VFR recordings
- If you believe the rates are actually equivalent (e.g. 30/1 vs 30000/1001 rounding), normalize them yourself — the library requires exact equality after normalization
Example fix
# before
info = resolve.probe_asset('screen_recording.mov') # VFR
# after
subprocess.run(['ffmpeg', '-i', 'screen_recording.mov', '-vsync', 'cfr', '-r', '30', 'cfr.mov'])
info = resolve.probe_asset('cfr.mov') Defensive patterns
Strategy: validation
Validate before calling
import json, subprocess
def is_constant_rate(path):
r = subprocess.run(['ffprobe', '-v', 'error', '-select_streams', 'v:0',
'-show_entries', 'stream=avg_frame_rate,r_frame_rate',
'-of', 'json', str(path)], capture_output=True, text=True)
s = json.loads(r.stdout)['streams'][0]
return s['avg_frame_rate'] == s['r_frame_rate']
assert is_constant_rate('cfr.mov') Try / catch
try:
info = resolve.probe_asset(path)
except ValueError as e:
if 'variable or ambiguous frame rate' in str(e):
cfr = conform_to_cfr(path, fps=30)
info = resolve.probe_asset(cfr)
else:
raise Prevention
- Record screen captures at constant frame rate (OBS: CFR mode)
- Always re-encode VFR footage to CFR before compositing
- Probe every asset during ingest and reject VFR early
When it happens
Trigger: Probing screen recordings or phone footage encoded with variable frame rate (avg_frame_rate='30000/1001' vs r_frame_rate='60000/1001'); probing files where ffprobe reports r_frame_rate like '0/0' or '1000/1' inconsistent with the average.
Common situations: OBS/phone screen recordings (commonly VFR); footage re-cut in an editor that produced VFR output; mkv files with default/inherited per-frame rates that disagree with the average.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- asset must contain a video stream
- output width and height must be positive
- source fps must be finite and positive; provide --fps
- 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/f8a0ab84efdd2716.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/resolve.py:66
"-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",
}
return {
"fps": str(average),
"frames": int(stream["nb_read_frames"]),
"has_alpha": alpha,View on GitHub (pinned to 8321021c54)