affaan-m/ECC · error · RuntimeError

ffmpeg failed

Error message

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

What it means

frames_to_video encodes a numbered PNG sequence (e.g. turn_%04d.png) into an H.264 video with ffmpeg. If ffmpeg exits non-zero, it raises RuntimeError with the last 400 characters of ffmpeg's stderr. Since the input is a filename pattern, the usual failure is that the pattern matched nothing or the frames are malformed, which ffmpeg reports as an impossible-to-open input.

Solutions

  1. Read the stderr tail in the exception - 'No such file or directory' means the pattern matched nothing; 'Unknown encoder libx264' means the codec is missing.
  2. Verify the pattern against the real files: ls the frames directory and confirm padding/start number; add -start_number to the ffmpeg input options if the sequence starts at 1 (or adjust your pattern).
  3. Regenerate frames if corrupt, and make sure the glob used for counting matches the ffmpeg pattern exactly.
  4. Confirm libx264 is available (ffmpeg -version shows --enable-libx264) or switch to an available codec (e.g. -c:v mpeg4).
  5. Check dst's directory is writable and has space; quote any pattern containing spaces when constructing the command.

Example fix

// before
frames_to_video('renders/turn_%03d.png', 'out.mp4')  # files are turn_0001.png (4-digit, starts at 1)
// after
subprocess.run(['ffmpeg','-y','-framerate','24','-start_number','1','-i','renders/turn_%04d.png','-c:v','libx264','-pix_fmt','yuv420p','out.mp4'], check=True)
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
import re
# confirm the pattern matches the frames that actually exist
frames = sorted(Path(pattern_dir).glob('turn_*.png'))
assert frames, f'no frames match in {pattern_dir}'
nums = [int(re.search(r'(\d+)\.png$', f.name).group(1)) for f in frames]
padding = len(re.search(r'\d+', frames[0].name).group(0))
print(f'{len(frames)} frames, start={min(nums)}, padding={padding}')  # build pattern from these facts

Try / catch

try:
    frames_to_video(pattern, dst)
except RuntimeError as e:
    msg = str(e).split(': ', 1)[-1]
    if 'No such file' in msg:
        raise SystemExit('frame pattern mismatch: check padding and -start_number') from e
    if 'libx264' in msg:
        raise SystemExit('ffmpeg lacks libx264; install a full build') from e
    raise

Prevention

When it happens

Trigger: frames_to_video(pattern, dst) fails when: the pattern doesn't match actual filenames (wrong padding, e.g. %03d vs turn_0001.png), frames live in a different directory than the pattern assumes, ffmpeg lacks libx264, dst is unwritable, or a source frame is corrupt so decoding aborts.

Common situations: Off-by-one start number (sequence starts at 0 or 1 while the pattern implies another), renamed/alphabetically-sorted frames with inconsistent zero padding, headless CI ffmpeg without libx264, spaces or special chars in the unquoted pattern, or dst in a read-only output directory.

Related errors


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

Appendix: source

Thrown at skills/taste-distillation/scripts/taste/render3d.py:288

        except Exception:
            # A failed Blender render must not lose the asset; the software
            # path always works, so degrade instead of raising.
            pass
    return turntable_software(mesh_path, dest, n_frames, size), "software"


def frames_to_video(frames: list[Path], dst: str | Path, fps: float = 24.0) -> Path:
    """Encode rendered frames into a clip the rest of the pipeline can eat."""
    dst = Path(dst)
    dst.parent.mkdir(parents=True, exist_ok=True)
    pattern = str(frames[0].parent / "turn_%04d.png")
    proc = subprocess.run([
        "ffmpeg", "-nostdin", "-loglevel", "error", "-y",
        "-framerate", f"{fps:g}", "-i", pattern,
        "-c:v", "libx264", "-crf", "14", "-pix_fmt", "yuv420p", str(dst),
    ], capture_output=True, text=True)
    if proc.returncode != 0:
        raise RuntimeError(f"ffmpeg failed: {proc.stderr[-400:]}")
    return dst

View on GitHub (pinned to 8321021c54)