affaan-m/ECC · error · RuntimeError

ffmpeg failed: ...

Error message

ffmpeg failed: {' '.join(cmd[:6])}...
{proc.stderr[-400:]}

What it means

This RuntimeError is raised by the internal _run() helper in assemble.py whenever an ffmpeg subprocess exits with a non-zero return code. The message includes the first six argv tokens (to identify the operation: cut_take, overlay, concat, or normalize) and the last 400 characters of ffmpeg's stderr for diagnosis. It is a generic wrapper: the real cause is always in the captured stderr.

Solutions

  1. Read the stderr tail in the message (after the '...') — it contains ffmpeg's actual error; fix the option/filter it complains about
  2. Run the exact ffmpeg command shown in the message manually with full arguments to reproduce and iterate on the failure
  3. Verify the input file exists and is decodable: ffprobe <input>
  4. Check the output path/extension maps to a supported muxer/codec
  5. Confirm ffmpeg is installed and on PATH (ffmpeg -version) and matches expected version behavior

Example fix

# before
_run(["ffmpeg", "-i", src, "-vf", "pad=-10:-10", out])  # negative pad kills filtergraph
# after
_run(["ffmpeg", "-i", src, "-vf", f"pad={width}:{height}:0:0", out])  # valid non-negative offsets
Defensive patterns

Strategy: try-catch

Validate before calling

import shutil
assert shutil.which("ffmpeg"), "ffmpeg not on PATH"
import subprocess
probe = subprocess.run(["ffprobe", "-v", "error", str(src)], capture_output=True, text=True)
assert probe.returncode == 0, f"undecodable input: {probe.stderr}"

Try / catch

try:
    cut_take(src, shots, dest)
except RuntimeError as e:
    msg = str(e)
    stderr_tail = msg.split("...", 1)[-1]
    print(f"ffmpeg failed:\n{stderr_tail}")  # inspect and fix the offending command
    raise

Prevention

When it happens

Trigger: Any call to cut_take(), overlay(), concat(), or normalize() where the constructed ffmpeg command fails — e.g. invalid filter graph syntax, missing input file, unsupported codec/parameters, or a malformed output path — since _run() propagates every subprocess failure as this RuntimeError.

Common situations: Building a filter_complex string with an invalid pad/scale expression; pointing cut_take at a source ffmpeg cannot decode; requesting an output format/extension ffmpeg doesn't recognize; a broken ffmpeg installation or wrong binary on PATH producing option errors.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/a085c1388fcb6f03. Report an issue: GitHub.

Appendix: source

Thrown at skills/taste-application/scripts/taste/assemble.py:31

  new material into it;
* **the cut itself**, at the reference's measured cadence rather than at
  whatever length the generator happened to emit.
"""

from __future__ import annotations

import json
import subprocess
from pathlib import Path

from . import cadence as cad_mod
from . import frames as frame_mod


def _run(cmd: list[str]) -> None:
    proc = subprocess.run(cmd, capture_output=True, text=True)
    if proc.returncode != 0:
        raise RuntimeError(f"ffmpeg failed: {' '.join(cmd[:6])}...\n{proc.stderr[-400:]}")


def cut_take(
    src: str | Path,
    shots: list[dict],
    dest_dir: str | Path,
    prefix: str = "shot",
    fps: float | None = None,
) -> list[Path]:
    """Slice one generated take into its planned sub-shots.

    Re-encodes rather than stream-copying. Stream copy can only cut on
    keyframes, and at a mean shot length of 0.78s that rounds every boundary
    to the nearest GOP - which is precisely the rhythm this whole pipeline
    exists to preserve.
    """
    src, dest_dir = Path(src), Path(dest_dir)
    dest_dir.mkdir(parents=True, exist_ok=True)

View on GitHub (pinned to 8321021c54)