{"record":{"id":"760fc0f707811b06","repo":"affaan-m/ECC","slug":"analyze-needs-at-least-one-frame-grade","errorCode":null,"errorMessage":"analyze() needs at least one frame","messagePattern":"analyze\\(\\) needs at least one frame","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-distillation/scripts/taste/grade.py","lineNumber":214,"sourceCode":"    populated = [i for i, v in enumerate(raw) if v is not None]\n    if not populated:\n        g = [float(a.mean()), float(a.std()), float(b.mean()), float(b.std())]\n        return [list(g) for _ in range(_N_ZONES)]\n\n    out: list[list] = []\n    for z in range(_N_ZONES):\n        if raw[z] is not None:\n            out.append(raw[z])\n        else:\n            nearest = min(populated, key=lambda p: abs(p - z))\n            out.append(list(raw[nearest]))\n    return out\n\n\ndef analyze(frames: list[np.ndarray]) -> GradeStats:\n    \"\"\"Distill grade statistics from a list of float32 RGB frames in [0,1].\"\"\"\n    if not frames:\n        raise ValueError(\"analyze() needs at least one frame\")\n\n    labs = [_to_lab(f) for f in frames]\n    stacked = np.concatenate([l.reshape(-1, 3) for l in labs], axis=0)\n    L, a, b = stacked[:, 0], stacked[:, 1], stacked[:, 2]\n\n    chroma = np.sqrt(a.astype(np.float64) ** 2 + b.astype(np.float64) ** 2)\n\n    return GradeStats(\n        zones=_zone_stats(L, a, b),\n        lab_mean=[float(L.mean()), float(a.mean()), float(b.mean())],\n        lab_std=[float(L.std()), float(a.std()), float(b.std())],\n        l_cdf=[float(v) for v in _cdf_of_l(L)],\n        black_point=float(np.percentile(L, 1)),\n        white_point=float(np.percentile(L, 99)),\n        contrast=float(L.std()),\n        saturation=float(chroma.mean()),\n        warmth=float(b.mean()),\n        tint=float(a.mean()),","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-distillation/scripts/taste/grade.py#L196-L232","documentation":"analyze() computes grade statistics from a list of decoded frames and rejects empty input up front, because downstream concatenation and percentile math would produce NaNs or IndexError on an empty stack. It is a defensive guard for callers that skipped or failed frame extraction.","triggerScenarios":"Calling analyze([]) after sample_frames() returned nothing, after filtering out all frames, or when frame extraction was skipped due to an earlier (swallowed) error.","commonSituations":"Pipelines that catch the 'decoded zero frames' error and continue with an empty list; masking/filter logic that discards every frame; initializing accumulator lists that never got populated.","solutions":["Guard with `if frames:` before calling analyze() and handle the empty case explicitly","Ensure sample_frames() succeeded and returned a non-empty list before analysis","If frames may be filtered, raise or log earlier instead of passing an empty list downstream","Catch ValueError and skip the clip with a warning if empty input is expected sometimes"],"exampleFix":"// before\nstats = analyze(frames)  # ValueError on empty list\n// after\nif not frames:\n    raise SkipClip(\"no frames to analyze\")\nstats = analyze(frames)","handlingStrategy":"validation","validationCode":"if not frames:\n    raise ValueError(\"no frames extracted; refusing to analyze\")","typeGuard":null,"tryCatchPattern":"try:\n    stats = analyze(frames)\nexcept ValueError as e:\n    if \"needs at least one frame\" in str(e):\n        log.warning(\"skipping clip: no frames\"); stats = None\n    else: raise","preventionTips":["Never call analyze() on a list you have not length-checked","Handle sample_frames() failures by skipping the clip, not by proceeding with []","Assert non-empty frames at pipeline stage boundaries"],"tags":["video","validation","numpy"],"backgroundTag":"empty-required-field","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"}