{"record":{"id":"897c7e9e0025a031","repo":"roboflow/supervision","slug":"length-of-color-lookup-len-color-lookup-does-no","errorCode":null,"errorMessage":"Length of color lookup {len(color_lookup)} does not match length of detections {len(detections)}","messagePattern":"Length of color lookup (.+?) does not match length of detections (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/annotators/utils.py","lineNumber":51,"sourceCode":"    @classmethod\n    def list(cls) -> list[str]:\n        return list(map(lambda c: c.value, cls))\n\n\ndef resolve_color_idx(\n    detections: Detections,\n    detection_idx: int,\n    color_lookup: ColorLookup | npt.NDArray[np.int_] = ColorLookup.CLASS,\n) -> int:\n    if detection_idx >= len(detections):\n        raise ValueError(\n            f\"Detection index {detection_idx} \"\n            f\"is out of bounds for detections of length {len(detections)}\"\n        )\n\n    if isinstance(color_lookup, np.ndarray):\n        if len(color_lookup) != len(detections):\n            raise ValueError(\n                f\"Length of color lookup {len(color_lookup)} \"\n                f\"does not match length of detections {len(detections)}\"\n            )\n        return int(color_lookup[detection_idx])\n    elif color_lookup == ColorLookup.INDEX:\n        return detection_idx\n    elif color_lookup == ColorLookup.CLASS:\n        if detections.class_id is None:\n            raise ValueError(\n                \"Could not resolve color by class because \"\n                \"Detections do not have class_id. If using an annotator, \"\n                \"try setting color_lookup to sv.ColorLookup.INDEX or \"\n                \"sv.ColorLookup.TRACK.\"\n            )\n        return int(detections.class_id[detection_idx])\n    elif color_lookup == ColorLookup.TRACK:\n        if detections.tracker_id is None:\n            raise ValueError(","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/annotators/utils.py#L33-L69","documentation":"Raised by `resolve_color_idx` in `supervision.annotators/utils.py` when a custom `color_lookup` is passed as a NumPy array whose length differs from the number of detections. The array maps each detection index to a palette/color index, so it must be aligned 1:1 with `detections`.","triggerScenarios":"Calling an annotator's `annotate(scene, detections, custom_color_lookup=np.array([0, 1]))` when `len(detections) == 5`; reusing a `custom_color_lookup` array computed from last frame's detections while detections changed size after filtering (e.g. `detections = detections[detections.confidence > 0.5]`).","commonSituations":"Filtering detections (NMS, confidence threshold, zone filtering) between building the lookup array and calling annotate; caching a per-camera color mapping across frames with varying detection counts; passing class_id-derived lookups to a Detections whose length shrank after slicing.","solutions":["Recompute the lookup after any filtering so `len(custom_color_lookup) == len(detections)`.","Derive the array from the detections object itself at annotate time: `np.arange(len(detections))` or `detections.class_id`.","If colors should follow classes, drop the custom array and use the default `ColorLookup.CLASS`."],"exampleFix":"# before\nlookup = np.arange(len(detections))\ndetections = detections[detections.confidence > 0.5]  # length changed\nannotator.annotate(scene, detections, custom_color_lookup=lookup)  # ValueError\n\n# after\nlookup = np.arange(len(detections))\ndetections = detections[detections.confidence > 0.5]\nannotator.annotate(scene, detections, custom_color_lookup=np.arange(len(detections)))","handlingStrategy":"validation","validationCode":"lookup = np.asarray(custom_color_lookup)\nassert len(lookup) == len(detections), (\n    f\"lookup {len(lookup)} != detections {len(detections)}\"\n)\nannotator.annotate(scene, detections, custom_color_lookup=lookup)","typeGuard":null,"tryCatchPattern":"try:\n    annotator.annotate(scene, detections, custom_color_lookup=lookup)\nexcept ValueError as e:\n    if \"does not match length of detections\" in str(e):\n        lookup = np.arange(len(detections))  # rebuild and retry once\n        annotator.annotate(scene, detections, custom_color_lookup=lookup)\n    else:\n        raise","preventionTips":["Derive custom_color_lookup from detections at annotate time, never cache it across filtering steps.","Re-derive the lookup after every slice/filter of detections."],"tags":["annotators","color","alignment"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}