{"record":{"id":"f8a0ab84efdd2716","repo":"affaan-m/ECC","slug":"variable-or-ambiguous-frame-rate-path","errorCode":null,"errorMessage":"variable or ambiguous frame rate: {path}","messagePattern":"variable or ambiguous frame rate: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/resolve.py","lineNumber":66,"sourceCode":"            \"-count_frames\",\n            \"-show_entries\",\n            \"stream=avg_frame_rate,r_frame_rate,nb_read_frames,pix_fmt\",\n            \"-of\",\n            \"json\",\n            str(path),\n        ],\n        capture_output=True,\n        text=True,\n        check=True,\n        timeout=120,\n    )\n    streams = json.loads(result.stdout).get(\"streams\", [])\n    if len(streams) != 1:\n        raise ValueError(f\"asset must contain a video stream: {path}\")\n    stream = streams[0]\n    average = _fps(stream[\"avg_frame_rate\"])\n    if average != _fps(stream[\"r_frame_rate\"]):\n        raise ValueError(f\"variable or ambiguous frame rate: {path}\")\n    pixel_format = stream.get(\"pix_fmt\", \"\")\n    alpha = pixel_format.startswith((\"yuva\", \"gbrap\")) or pixel_format in {\n        \"rgba\",\n        \"bgra\",\n        \"argb\",\n        \"abgr\",\n        \"rgba64be\",\n        \"rgba64le\",\n        \"bgra64be\",\n        \"bgra64le\",\n        \"ya8\",\n        \"ya16be\",\n        \"ya16le\",\n    }\n    return {\n        \"fps\": str(average),\n        \"frames\": int(stream[\"nb_read_frames\"]),\n        \"has_alpha\": alpha,","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/resolve.py#L48-L84","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\ninfo = resolve.probe_asset('screen_recording.mov')  # VFR\n# after\nsubprocess.run(['ffmpeg', '-i', 'screen_recording.mov', '-vsync', 'cfr', '-r', '30', 'cfr.mov'])\ninfo = resolve.probe_asset('cfr.mov')","handlingStrategy":"validation","validationCode":"import json, subprocess\n\ndef is_constant_rate(path):\n    r = subprocess.run(['ffprobe', '-v', 'error', '-select_streams', 'v:0',\n                        '-show_entries', 'stream=avg_frame_rate,r_frame_rate',\n                        '-of', 'json', str(path)], capture_output=True, text=True)\n    s = json.loads(r.stdout)['streams'][0]\n    return s['avg_frame_rate'] == s['r_frame_rate']\n\nassert is_constant_rate('cfr.mov')","typeGuard":null,"tryCatchPattern":"try:\n    info = resolve.probe_asset(path)\nexcept ValueError as e:\n    if 'variable or ambiguous frame rate' in str(e):\n        cfr = conform_to_cfr(path, fps=30)\n        info = resolve.probe_asset(cfr)\n    else:\n        raise","preventionTips":["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"],"tags":["video","ffprobe","frame-rate"],"backgroundTag":"invalid-argument-value","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}