{"record":{"id":"82b8fbe5c6640469","repo":"babysor/MockingBird","slug":"ffmpeg-not-found-in-path","errorCode":null,"errorMessage":"ffmpeg not found in PATH.","messagePattern":"ffmpeg not found in PATH\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"critical","filePath":"skills/speak/scripts/render_timeline.py","lineNumber":123,"sourceCode":"    for key, seg_cfg in config.get(\"segments\", {}).items():\n        lo, hi = parse_segment_key(key)\n        if lo <= index <= hi:\n            merged.update(seg_cfg)\n    return merged\n\n\n# ── ffmpeg helpers ────────────────────────────────────────────────────\n\n\ndef _run_ff(cmd: List[str]) -> None:\n    proc = subprocess.run(cmd, capture_output=True, text=True)\n    if proc.returncode != 0:\n        raise RuntimeError(f\"ffmpeg failed: {' '.join(cmd)}\\n{proc.stderr}\")\n\n\ndef ensure_ffmpeg() -> None:\n    if not shutil.which(\"ffmpeg\"):\n        raise RuntimeError(\"ffmpeg not found in PATH.\")\n\n\ndef probe_duration_ms(path: Path) -> float:\n    proc = subprocess.run(\n        [\n            \"ffprobe\", \"-v\", \"error\", \"-show_entries\", \"format=duration\",\n            \"-of\", \"default=noprint_wrappers=1:nokey=1\", str(path),\n        ],\n        capture_output=True, text=True,\n    )\n    if proc.returncode != 0:\n        raise RuntimeError(f\"ffprobe failed on {path}: {proc.stderr}\")\n    return float(proc.stdout.strip()) * 1000\n\n\ndef normalize_duration_pad_trim(inp: Path, outp: Path, target_ms: int) -> None:\n    \"\"\"Pad short audio then trim to exact target duration (Noiz backend).\"\"\"\n    sec = target_ms / 1000.0","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/babysor/MockingBird/blob/28dc5e14f12d7c754612af2fde8e78a4b03f8616/skills/speak/scripts/render_timeline.py#L105-L141","documentation":"RuntimeError raised by ensure_ffmpeg when shutil.which('ffmpeg') returns None, i.e. the ffmpeg binary is not on PATH. render_timeline requires ffmpeg for all normalization and mixing, so this is a hard startup check.","triggerScenarios":"Running the script on a machine/container without ffmpeg installed, in a venv whose PATH shadows the binary, or in a minimal Docker image.","commonSituations":"Fresh macOS/Linux without brew/apt install, slim Docker images, CI runners, or SSH sessions with a minimal PATH.","solutions":["Install ffmpeg: brew install ffmpeg / apt-get install ffmpeg / use a static build","Verify with: ffmpeg -version","If installed but not found, add its directory to PATH or invoke the script from a shell with the correct profile loaded"],"exampleFix":"# before (missing)\n# after\napt-get update && apt-get install -y ffmpeg  # Debian/Ubuntu\nbrew install ffmpeg                        # macOS","handlingStrategy":"validation","validationCode":"import shutil\nif not shutil.which('ffmpeg'):\n    sys.exit('Install ffmpeg first: apt-get install ffmpeg')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Install ffmpeg in base images/CI","Add a startup dependency check","Document the binary requirement"],"tags":["ffmpeg","environment","dependency","path"],"backgroundTag":"missing-system-dependency","analyzedSha":"28dc5e14f12d7c754612af2fde8e78a4b03f8616","analyzedAt":"2026-08-27T02:26:53.589Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}