affaan-m/ECC · error · ValueError

Crop must contain four finite values

Error message

Crop must contain four finite values

What it means

filter_graph() validates the start and end camera-crop rectangles used for the animated zoompan. Each crop must be a sequence of exactly four finite numbers; it raises ValueError('Crop must contain four finite values') otherwise. A second check ensures each rect fits within normalized [0,1] coordinates.

Solutions

  1. Pass exactly four numbers [x, y, w, h] for both start and end crops
  2. Validate length and finiteness before calling: len(c) == 4 and all(math.isfinite(v) for v in c)
  3. Fix the config/data source producing short or NaN crop lists
  4. Check argument order — start and end are both crop rectangles, not timestamps

Example fix

// before
make_clip(src, start=[0.1, 0.1, 0.5], end=[0, 0, 1, 1], ...)  # only 3 values
// after
make_clip(src, start=[0.1, 0.1, 0.5, 0.5], end=[0, 0, 1, 1], ...)
Defensive patterns

Strategy: validation

Validate before calling

import math
def valid_crop(c):
    return (isinstance(c, (list, tuple)) and len(c) == 4
            and all(isinstance(v, (int, float)) and math.isfinite(v) for v in c))
assert valid_crop(start_crop) and valid_crop(end_crop)

Type guard

def is_valid_crop(c) -> bool:
    return (isinstance(c, (list, tuple)) and len(c) == 4
            and all(isinstance(v, (int, float)) and not isinstance(v, bool) and math.isfinite(v) for v in c))

Try / catch

try:
    make_clip(src, start=start_crop, end=end_crop, output=out)
except ValueError as e:
    if 'Crop must contain four finite values' in str(e):
        start_crop, end_crop = [0, 0, 1, 1], [0, 0, 1, 1]  # safe full-frame default

Prevention

When it happens

Trigger: Passing start/end crops with fewer or more than 4 elements (e.g. [x, y, w]); passing NaN or inf values from unparsed config; passing None or a non-iterable as start.

Common situations: Loading crop values from JSON/YAML where a key is missing so the list is short; computing crops with a division that produced NaN (0/0); swapping argument order so a scalar is passed where a 4-tuple is expected.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at skills/taste-application/scripts/tasteforge/media/stills.py:14

"""Animate an image between normalized crop rectangles using local FFmpeg."""

import argparse
import math
import subprocess
from pathlib import Path

from .common import geometry, output_file


def filter_graph(start, end, frames, width, height, fps):
    for crop in (start, end):
        if len(crop) != 4 or any(not math.isfinite(v) for v in crop):
            raise ValueError("Crop must contain four finite values")
        x, y, w, h = crop
        if min(x, y) < 0 or min(w, h) <= 0 or x + w > 1 or y + h > 1:
            raise ValueError("Crop must fit within normalized image coordinates")
    # Coordinates refer to the image after scale-cover to output aspect.
    # Expand each requested rectangle to output aspect, then interpolate its
    # width and center; zoompan clamps the window at image boundaries.
    fraction = f"on/{max(1, frames - 1)}"

    def interpolate(a, b):
        return f"({a}+({b}-{a})*{fraction})"

    zoom = f"1/{interpolate(max(start[2], start[3]), max(end[2], end[3]))}"
    cx = interpolate(start[0] + start[2] / 2, end[0] + end[2] / 2)
    cy = interpolate(start[1] + start[3] / 2, end[1] + end[3] / 2)
    return (
        f"scale={width * 2}:{height * 2}:force_original_aspect_ratio=increase,"
        f"crop={width * 2}:{height * 2},zoompan=z='{zoom}':"
        f"x='iw*{cx}-iw/zoom/2':y='ih*{cy}-ih/zoom/2':"

View on GitHub (pinned to 8321021c54)