{"record":{"id":"372352f37911c6b8","repo":"calesthio/OpenMontage","slug":"ffmpeg-failed-to-render-preview-mp4","errorCode":null,"errorMessage":"ffmpeg failed to render preview MP4","messagePattern":"ffmpeg failed to render preview MP4","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"tools/character/character_animation.py","lineNumber":106,"sourceCode":"            page.screenshot(path=str(frame_dir / f\"frame_{frame:04d}.png\"))\n        browser.close()\n\n    cmd = [\n        \"ffmpeg\",\n        \"-y\",\n        \"-framerate\",\n        str(fps),\n        \"-i\",\n        str(frame_dir / \"frame_%04d.png\"),\n        \"-r\",\n        str(fps),\n        \"-pix_fmt\",\n        \"yuv420p\",\n        str(video_path),\n    ]\n    result = subprocess.run(cmd, capture_output=True, text=True)\n    if result.returncode != 0:\n        raise RuntimeError(result.stderr.strip() or \"ffmpeg failed to render preview MP4\")\n\n\nclass CharacterSpecGenerator(BaseTool):\n    name = \"character_spec_generator\"\n    version = \"0.1.0\"\n    tier = ToolTier.CORE\n    capability = \"character_animation\"\n    provider = \"openmontage\"\n    stability = ToolStability.BETA\n    execution_mode = ExecutionMode.SYNC\n    determinism = Determinism.DETERMINISTIC\n    resource_profile = ResourceProfile(cpu_cores=1, ram_mb=128, vram_mb=0, disk_mb=10)\n    agent_skills = [\"character-rigging\", \"pose-library-design\"]\n    capabilities = [\"draft_character_design\", \"normalize_character_specs\"]\n    best_for = [\"Converting approved concepts into structured character_design artifacts\"]\n    not_good_for = [\"Generating artwork pixels or finished animation\"]\n    input_schema = {\n        \"type\": \"object\",","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/character/character_animation.py#L88-L124","documentation":"Raised after subprocess.run of the ffmpeg encode command when result.returncode != 0. The message is `result.stderr.strip() or 'ffmpeg failed to render preview MP4'` — i.e. the generic text only appears when ffmpeg produced empty stderr; normally you see ffmpeg's own error output. Common underlying causes are a codec/pixel-format mismatch with the output container, an unwritable output path, or ffmpeg builds missing encoders (e.g. static builds without libx264).","triggerScenarios":"ffmpeg exits non-zero while encoding the captured frame_%04d.png sequence into the preview MP4 (command uses -framerate fps -i frame_%04d.png -r fps -pix_fmt yuv420p <video_path>). Happens when the output path's extension selects a muxer/encoder the build lacks, the output directory does not exist or is not writable, or frames were not actually captured.","commonSituations":"video_path ending in a container the distro ffmpeg cannot encode (e.g. .mp4 without libx264 on a minimal build), read-only output dirs, disk full, leftover frame directories with gaps in numbering, or an output path whose parent was never created.","solutions":["Read the stderr captured in the exception message — it names the exact ffmpeg failure (unknown encoder, permission denied, no such file).","If stderr says 'Unknown encoder libx264', install a full ffmpeg build (brew/conda/apt mainline build) instead of a stripped static one, or confirm the output is .mp4 with an available encoder.","Ensure the output directory exists and is writable: create video_path.parent and check permissions before rendering.","Check that the frame directory actually contains frame_0000.png onward with no numbering gaps; re-run capture if screenshots failed silently."],"exampleFix":"# before\nvideo_path = out_dir / f\"{name}.mp4\"   # out_dir may not exist -> ffmpeg 'No such file or directory'\n\n# after\nvideo_path = out_dir / f\"{name}.mp4\"\nvideo_path.parent.mkdir(parents=True, exist_ok=True)\nresult = subprocess.run(cmd, capture_output=True, text=True)\nif result.returncode != 0:\n    raise RuntimeError(result.stderr.strip() or \"ffmpeg failed to render preview MP4\")","handlingStrategy":"try-catch","validationCode":"from pathlib import Path\n\ndef validate_encode(video_path: Path, frame_dir: Path) -> None:\n    video_path.parent.mkdir(parents=True, exist_ok=True)\n    frames = sorted(frame_dir.glob(\"frame_*.png\"))\n    assert frames, \"no frames captured for ffmpeg\"\n    assert video_path.parent.is_dir() and os.access(video_path.parent, os.W_OK), \"output dir not writable\"","typeGuard":null,"tryCatchPattern":"try:\n    _render_preview_mp4(preview, video, duration, fps)\nexcept RuntimeError as e:\n    stderr = str(e)\n    if \"Unknown encoder\" in stderr or \"ffmpeg failed\" in stderr:\n        log.error(\"ffmpeg encode failed: %s\", stderr)\n        raise\n    raise","preventionTips":["Always create the output parent directory before encoding.","Log result.stderr on any non-zero ffmpeg exit; never discard it.","Use a full-featured ffmpeg build in deployment images to guarantee libx264 availability."],"tags":["ffmpeg","subprocess","encoding","filesystem","character-animation"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}