{"record":{"id":"648cbfa834f3dee9","repo":"affaan-m/ECC","slug":"ffprobe-is-required-for-reference-probing","errorCode":null,"errorMessage":"ffprobe is required for reference probing","messagePattern":"ffprobe is required for reference probing","errorType":"exception","errorClass":"MediaToolUnavailable","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/workflow.py","lineNumber":371,"sourceCode":"        \"scale=320:-2,\"\n        \"select='not(mod(n\\\\,12))+gt(scene\\\\,0.30)',\"\n        \"signalstats,metadata=print:file=-\"\n    )\n    result = subprocess.run(\n        [ffmpeg, \"-v\", \"error\", \"-i\", str(path), \"-vf\", filters,\n         \"-an\", \"-vsync\", \"0\", \"-f\", \"null\", \"-\"],\n        check=True,\n        capture_output=True,\n        text=True,\n    )\n    return parse_feature_output(result.stderr + \"\\n\" + result.stdout)\n\n\ndef probe_media(path: Path) -> dict[str, Any]:\n    \"\"\"Probe local media and extract timestamped style/temporal features.\"\"\"\n    ffprobe = shutil.which(\"ffprobe\")\n    if not ffprobe:\n        raise MediaToolUnavailable(\"ffprobe is required for reference probing\")\n    command = [\n        ffprobe, \"-v\", \"error\", \"-show_streams\", \"-show_format\",\n        \"-of\", \"json\", str(path),\n    ]\n    result = subprocess.run(command, check=True, capture_output=True, text=True)\n    payload = json.loads(result.stdout)\n    video: dict[str, Any] = next(\n        (stream for stream in payload.get(\"streams\", []) if stream.get(\"codec_type\") == \"video\"),\n        {},\n    )\n    duration = float(video.get(\"duration\") or payload.get(\"format\", {}).get(\"duration\") or 0)\n    rate = str(video.get(\"avg_frame_rate\") or video.get(\"r_frame_rate\") or \"0/1\")\n    num, _, den = rate.partition(\"/\")\n    fps = float(num) / float(den or 1) if float(den or 1) else 0.0\n    feature_data = _run_ffmpeg_features(path)\n    measured_times = sorted({\n        float(sample[\"time\"]) for sample in feature_data[\"style_samples\"]\n    } | set(feature_data[\"scene_changes\"]))","sourceCodeStart":353,"sourceCodeEnd":389,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/workflow.py#L353-L389","documentation":"probe_media needs ffprobe on PATH to read timestamped style/temporal features from local media; shutil.which('ffprobe') returned nothing, so the environment is missing the ffmpeg toolset.","triggerScenarios":"probe_media(path) invoked while shutil.which('ffprobe') is None — ffprobe not installed, or ffmpeg installed without ffprobe (rare minimal builds).","commonSituations":"Slim container images with ffmpeg but stripped ffprobe; partially installed/removed ffmpeg packages; PATH not including /usr/bin in service contexts.","solutions":["Install the full ffmpeg package so ffprobe ships alongside it (apt install ffmpeg)","Verify with `which ffprobe` in the same environment that runs the workflow","Fix PATH for the execution context (cron/systemd/CI often have a minimal PATH)"],"exampleFix":"# before\n$ which ffprobe   # (empty)\n# after\n$ sudo apt-get install -y ffmpeg && which ffprobe\n/usr/bin/ffprobe","handlingStrategy":"validation","validationCode":"import shutil\nmissing = [t for t in (\"ffmpeg\", \"ffprobe\") if shutil.which(t) is None]\nif missing:\n    raise SystemExit(f\"missing media tools: {', '.join(missing)}\")","typeGuard":"def has_ffprobe() -> bool:\n    import shutil\n    return shutil.which(\"ffprobe\") is not None","tryCatchPattern":"try:\n    probe = probe_media(path)\nexcept MediaToolUnavailable as e:\n    logging.error(\"media tooling unavailable: %s\", e)\n    raise SystemExit(2)","preventionTips":["Install full ffmpeg packages, not stripped builds","Verify both ffmpeg and ffprobe resolve on PATH in deployment scripts","Pin the ffmpeg package in Dockerfiles and CI"],"tags":["ffprobe","missing-binary","environment"],"backgroundTag":"missing-dependency","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"}