roboflow/supervision · error · ValueError

The number of predictions ({len(predictions)}) and targets (

Error message

The number of predictions ({len(predictions)}) and targets ({len(targets)}) during the update must be the same.

What it means

MeanAverageRecall.update() accepts either a single Detections or a list of Detections for predictions and targets, but the two arguments must describe the same images. This ValueError fires when, after list-wrapping, len(predictions) != len(targets) — i.e. you passed a different number of prediction frames than ground-truth frames. The metric pairs them index-by-index, so a mismatch would silently misalign evaluations, hence the hard failure.

Source

Thrown at src/supervision/metrics/mean_average_recall.py:355

        targets: Detections | list[Detections],
    ) -> MeanAverageRecall:
        """
        Add new predictions and targets to the metric, but do not compute the result.

        Args:
            predictions: The predicted detections.
            targets: The target detections.

        Returns:
            The updated metric instance.
        """
        if not isinstance(predictions, list):
            predictions = [predictions]
        if not isinstance(targets, list):
            targets = [targets]

        if len(predictions) != len(targets):
            raise ValueError(
                f"The number of predictions ({len(predictions)}) and"
                f" targets ({len(targets)}) during the update must be the same."
            )

        self._predictions_list.extend(predictions)
        self._targets_list.extend(targets)

        return self

    def compute(self) -> MeanAverageRecallResult:
        """
        Calculate the Mean Average Recall metric based on the stored predictions
        and ground-truth, at different IoU thresholds and maximum detection counts.

        Returns:
            The Mean Average Recall metric result.
        """
        result = self._compute(self._predictions_list, self._targets_list)

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Ensure both arguments are lists of equal length, one entry per image: mar.update(list_of_preds, list_of_targets) with len equal
  2. If a frame has no predictions, still pass an empty sv.Detections.empty() placeholder so indexes stay aligned
  3. Audit accumulation loops: append to both lists in the same iteration, never conditionally to one
  4. Add an assert len(preds)==len(targets) before update() in pipeline code to fail at the call site with your own context

Example fix

# before
for frame in frames:
    preds.append(model(frame))
    if frame.has_annotation:  # targets appended conditionally -> length drift
        targets.append(frame.targets)
mar.update(preds, targets)

# after
for frame in frames:
    preds.append(model(frame))
    targets.append(frame.targets if frame.has_annotation else sv.Detections.empty())
assert len(preds) == len(targets)
mar.update(preds, targets)
Defensive patterns

Strategy: validation

Validate before calling

from supervision.detection.core import Detections

def safe_update(mar, preds, tgts):
    """Update MAR only when per-image counts align."""
    preds = preds if isinstance(preds, list) else [preds]
    tgts = tgts if isinstance(tgts, list) else [tgts]
    if len(preds) != len(tgts):
        raise ValueError(f'{len(preds)} preds vs {len(tgts)} targets')
    return mar.update(preds, tgts)

Type guard

from typing import Union, List
from supervision.detection.core import Detections

def is_paired_detection_lists(
    preds: Union[Detections, List[Detections]],
    tgts: Union[Detections, List[Detections]],
) -> bool:
    """True when both sides normalize to equal-length per-image lists."""
    p = preds if isinstance(preds, list) else [preds]
    t = tgts if isinstance(tgts, list) else [tgts]
    return len(p) == len(t)

Prevention

When it happens

Trigger: Calling mar.update([pred1, pred2], [target1]) or mar.update(preds_list, targets_list) where the lists have different lengths; wrapping only one side in a list (update([p], t) on a non-empty target with empty predictions list vs single Detections); accumulating predictions in a loop but appending targets only on some frames.

Common situations: Streaming video frames where the model skips frames (NVR dropout, inference exceptions swallowed) so prediction list grows slower than targets; batching predictions per image but passing all targets as one Detections; off-by-one when appending the first/last frame.

Related errors


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