roboflow/supervision · error · ValueError

Could not resolve color by track because Detections do not h

Error message

Could not resolve color by track because Detections do not have tracker_id. Did you call tracker.update_with_detections(...) before annotating?

What it means

Raised by `resolve_color_idx` when `color_lookup=ColorLookup.TRACK` is selected but `detections.tracker_id` is None. Track-based coloring needs per-detection tracker ids so each object keeps a stable color across frames.

Source

Thrown at src/supervision/annotators/utils.py:69

            raise ValueError(
                f"Length of color lookup {len(color_lookup)} "
                f"does not match length of detections {len(detections)}"
            )
        return int(color_lookup[detection_idx])
    elif color_lookup == ColorLookup.INDEX:
        return detection_idx
    elif color_lookup == ColorLookup.CLASS:
        if detections.class_id is None:
            raise ValueError(
                "Could not resolve color by class because "
                "Detections do not have class_id. If using an annotator, "
                "try setting color_lookup to sv.ColorLookup.INDEX or "
                "sv.ColorLookup.TRACK."
            )
        return int(detections.class_id[detection_idx])
    elif color_lookup == ColorLookup.TRACK:
        if detections.tracker_id is None:
            raise ValueError(
                "Could not resolve color by track because "
                "Detections do not have tracker_id. Did you call "
                "tracker.update_with_detections(...) before annotating?"
            )
        return int(detections.tracker_id[detection_idx])
    raise ValueError(f"Unsupported color lookup strategy: {color_lookup}")


def resolve_text_background_xyxy(
    center_coordinates: tuple[int, int],
    text_wh: tuple[int, int],
    position: Position,
) -> tuple[int, int, int, int]:
    """Compute the background box for text anchored at `position`."""
    center_x, center_y = center_coordinates
    text_w, text_h = text_wh

    if position == Position.TOP_LEFT:

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Move the annotate call after `detections = tracker.update_with_detections(detections)`.
  2. If tracking is not intended, switch to `ColorLookup.INDEX` or `ColorLookup.CLASS`.
  3. Ensure every code path through the frame loop produces tracker-updated detections before annotating.

Example fix

# before
annotator = sv.BoxAnnotator(color_lookup=sv.ColorLookup.TRACK)
scene = annotator.annotate(scene, detections)  # detections not tracked yet
tracker.update_with_detections(detections)

# after
annotator = sv.BoxAnnotator(color_lookup=sv.ColorLookup.TRACK)
detections = tracker.update_with_detections(detections)
scene = annotator.annotate(scene, detections)
Defensive patterns

Strategy: type-guard

Validate before calling

if annotator.color_lookup == sv.ColorLookup.TRACK and detections.tracker_id is None:
    detections = tracker.update_with_detections(detections)
annotator.annotate(scene, detections)

Type guard

def is_tracked(detections) -> bool:
    return detections.tracker_id is not None

Prevention

When it happens

Trigger: Constructing an annotator with `color_lookup=sv.ColorLookup.TRACK` and annotating detections that have not passed through `tracker.update_with_detections(...)`; annotating the first frame before the tracker call due to a loop-order bug; using a tracker's internal model results instead of the tracker's returned Detections.

Common situations: Reordering a video loop so annotation happens before tracking after a refactor; forgetting that only the Detections RETURNED by `update_with_detections` carry `tracker_id`; mixing tracked detections with freshly detected ones (e.g. concatenating) which can drop the field.

Related errors


AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15). Data as JSON: /api/errors/ff25bece31bc5526. Report an issue: GitHub.