affaan-m/ECC · error · RuntimeError

ffmpeg grade failed

Error message

ffmpeg grade failed: {proc.stderr[-400:]}

What it means

grade_clip shells out to ffmpeg with a lut3d video filter and libx264 encoding. If ffmpeg exits with a non-zero return code, the wrapper raises RuntimeError containing the last 400 characters of ffmpeg's stderr, because Python itself cannot diagnose ffmpeg-level failures. The real cause is always in the captured stderr text.

Solutions

  1. Read the stderr text embedded in the exception message - it names the specific ffmpeg error (filter parse error, codec missing, permission, etc.).
  2. Validate the LUT separately: run ffmpeg -i src -vf lut3d=file='your.cube' -frames:v 1 out.png to isolate whether the LUT or the clip is the problem.
  3. Check ffmpeg capabilities: ffmpeg -version and confirm libx264 appears in the configuration; if not, install a full ffmpeg build (e.g. via conda, brew, or a static build).
  4. Re-encode or remux the source if the input is corrupt/unsupported (ffmpeg -i src -c copy fixed.mp4), then grade the fixed file.
  5. Verify the destination directory is writable and has free space; test write with touch dst_dir/.probe.
Defensive patterns

Strategy: try-catch

Validate before calling

import shutil
assert shutil.which('ffmpeg'), 'ffmpeg not on PATH'
info = subprocess.run(['ffmpeg','-version'], capture_output=True, text=True)
assert 'libx264' in info.stderr or 'libx264' in info.stdout, 'ffmpeg lacks libx264'
assert Path(lut).is_file(), f'LUT missing: {lut}'

Try / catch

try:
    grade_clip(src, dst, lut=lut)
except RuntimeError as e:
    ffmpeg_err = str(e).split(': ', 1)[-1]
    logger.error('ffmpeg grading failed; stderr tail: %s', ffmpeg_err)
    # branch on the stderr content: LUT parse error vs codec vs permissions

Prevention

When it happens

Trigger: Any ffmpeg failure while grading: a malformed or unsupported .cube LUT the filter rejects, an unreadable/corrupt or unsupported input container/codec, a destination path that is not writable, or a broken ffmpeg install missing libx264.

Common situations: LUT exported with wrong size/format for lut3d (e.g. 1D LUT or non-cube LUT); ffmpeg on the system built without libx264; input video with a codec OpenCV/ffmpeg cannot decode; disk full or dst in a read-only directory; an old ffmpeg that lacks lut3d support.

Related errors


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

Appendix: source

Thrown at skills/taste-distillation/scripts/taste/grade.py:683

    s = max(0.0, min(1.0, float(strength)))
    if s >= 0.999:
        vf = f"lut3d=file='{lut.as_posix()}'"
    else:
        # Blend graded over original so partial looks stay available.
        vf = (
            f"split=2[a][b];[b]lut3d=file='{lut.as_posix()}'[g];"
            f"[a][g]blend=all_mode=normal:all_opacity={s:.3f}"
        )

    cmd = [
        "ffmpeg", "-nostdin", "-loglevel", "error", "-y", "-i", str(src),
        "-vf", vf, "-c:v", "libx264", "-crf", str(crf), "-pix_fmt", "yuv420p",
        "-c:a", "copy", str(dst),
    ]
    proc = subprocess.run(cmd, capture_output=True, text=True)
    if proc.returncode != 0:
        raise RuntimeError(f"ffmpeg grade failed: {proc.stderr[-400:]}")
    return dst


def grade_clip_adaptive(
    src: str | Path,
    dst: str | Path,
    target: GradeStats,
    strength: float = 1.0,
    lut_size: int = 33,
    n_frames: int = 32,
    keep_lut: str | Path | None = None,
) -> Path:
    """Measure the clip, bake a LUT *for that clip*, then apply it.

    Prefer this over :func:`grade_clip` for anything generated.

    ``look.cube`` is baked against a canonical neutral stand-in, because when
    a pack is minted there is no way to know what footage it will meet. That

View on GitHub (pinned to 8321021c54)