{"record":{"id":"a0056d1536541f38","repo":"affaan-m/ECC","slug":"crop-must-contain-four-finite-values","errorCode":null,"errorMessage":"Crop must contain four finite values","messagePattern":"Crop must contain four finite values","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/media/stills.py","lineNumber":14,"sourceCode":"\"\"\"Animate an image between normalized crop rectangles using local FFmpeg.\"\"\"\n\nimport argparse\nimport math\nimport subprocess\nfrom pathlib import Path\n\nfrom .common import geometry, output_file\n\n\ndef filter_graph(start, end, frames, width, height, fps):\n    for crop in (start, end):\n        if len(crop) != 4 or any(not math.isfinite(v) for v in crop):\n            raise ValueError(\"Crop must contain four finite values\")\n        x, y, w, h = crop\n        if min(x, y) < 0 or min(w, h) <= 0 or x + w > 1 or y + h > 1:\n            raise ValueError(\"Crop must fit within normalized image coordinates\")\n    # Coordinates refer to the image after scale-cover to output aspect.\n    # Expand each requested rectangle to output aspect, then interpolate its\n    # width and center; zoompan clamps the window at image boundaries.\n    fraction = f\"on/{max(1, frames - 1)}\"\n\n    def interpolate(a, b):\n        return f\"({a}+({b}-{a})*{fraction})\"\n\n    zoom = f\"1/{interpolate(max(start[2], start[3]), max(end[2], end[3]))}\"\n    cx = interpolate(start[0] + start[2] / 2, end[0] + end[2] / 2)\n    cy = interpolate(start[1] + start[3] / 2, end[1] + end[3] / 2)\n    return (\n        f\"scale={width * 2}:{height * 2}:force_original_aspect_ratio=increase,\"\n        f\"crop={width * 2}:{height * 2},zoompan=z='{zoom}':\"\n        f\"x='iw*{cx}-iw/zoom/2':y='ih*{cy}-ih/zoom/2':\"","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/media/stills.py#L1-L32","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass exactly four numbers [x, y, w, h] for both start and end crops","Validate length and finiteness before calling: len(c) == 4 and all(math.isfinite(v) for v in c)","Fix the config/data source producing short or NaN crop lists","Check argument order — start and end are both crop rectangles, not timestamps"],"exampleFix":"// before\nmake_clip(src, start=[0.1, 0.1, 0.5], end=[0, 0, 1, 1], ...)  # only 3 values\n// after\nmake_clip(src, start=[0.1, 0.1, 0.5, 0.5], end=[0, 0, 1, 1], ...)","handlingStrategy":"validation","validationCode":"import math\ndef valid_crop(c):\n    return (isinstance(c, (list, tuple)) and len(c) == 4\n            and all(isinstance(v, (int, float)) and math.isfinite(v) for v in c))\nassert valid_crop(start_crop) and valid_crop(end_crop)","typeGuard":"def is_valid_crop(c) -> bool:\n    return (isinstance(c, (list, tuple)) and len(c) == 4\n            and all(isinstance(v, (int, float)) and not isinstance(v, bool) and math.isfinite(v) for v in c))","tryCatchPattern":"try:\n    make_clip(src, start=start_crop, end=end_crop, output=out)\nexcept ValueError as e:\n    if 'Crop must contain four finite values' in str(e):\n        start_crop, end_crop = [0, 0, 1, 1], [0, 0, 1, 1]  # safe full-frame default","preventionTips":["Schema-validate crop config (4 finite numbers, within [0,1]) at load time","Guard divisions that compute crops to avoid NaN","Keep crop values in normalized [0,1] coordinates with w,h > 0","Sanity-check argument order: start and end are both crop rectangles, not timestamps"],"tags":["validation","argument-format","media"],"backgroundTag":"invalid-argument-format","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}