roboflow/supervision · error · ValueError
MeanAverageRecall metric requires `class_id` on both predict
Error message
MeanAverageRecall metric requires `class_id` on both predictions and targets.
What it means
MeanAverageRecall matches predictions to targets per class, so class_id must be present on both sides. This ValueError is raised inside compute() when, for an image with at least one ground-truth target, either predictions.class_id or targets.class_id is None. Note the check runs when len(targets) > 0: images with no ground truth skip it, and class-agnostic evaluation is not supported by this metric without ids.
Source
Thrown at src/supervision/metrics/mean_average_recall.py:409
) -> MeanAverageRecallResult:
if size_category != ObjectSizeCategory.ANY:
# Recall is unaffected by false-positive bookkeeping, and out-of-bucket
# predictions must still consume top-K rank slots, so bucket-filtering
# the targets is all the size handling mAR needs.
targets_list = [
self._filter_detections_by_size(targets, size_category)
for targets in targets_list
]
iou_thresholds = np.linspace(0.5, 0.95, 10, dtype=np.float32)
stats: list[Any] = []
for predictions, targets in zip(predictions_list, targets_list):
prediction_contents = self._detections_content(predictions)
target_contents = self._detections_content(targets)
if len(targets) > 0:
if predictions.class_id is None or targets.class_id is None:
raise ValueError(
"MeanAverageRecall metric requires `class_id` on both "
"predictions and targets."
)
if len(predictions) == 0:
target_class_ids = np.asarray(targets.class_id, dtype=np.int32)
if len(target_class_ids) == 0:
continue
stats.append(
(
np.zeros((0, iou_thresholds.size), dtype=bool),
np.zeros((0, iou_thresholds.size), dtype=bool),
np.zeros((0,), dtype=int),
np.zeros((0,), dtype=int),
target_class_ids,
)
)
else:View on GitHub (pinned to 7f254d9784)
Solutions
- Always pass class_id (np.int32/int64 array) when constructing sv.Detections for MAR evaluation
- For class-agnostic evaluation, assign a constant class_id=np.zeros(N, dtype=int) to both predictions and targets
- If using a model connector, ensure it maps class names to ids (e.g. via the model's names dict) before update()
- Validate before update(): if targets are non-empty, require class_id is not None on both sides
Example fix
# before
preds = sv.Detections(xyxy=boxes, confidence=confs) # class_id missing
mar.update(preds, targets)
# after
preds = sv.Detections(xyxy=boxes, confidence=confs,
class_id=class_ids) # required by MAR
targets = sv.Detections(xyxy=gt_boxes, class_id=gt_class_ids)
mar.update(preds, targets) Defensive patterns
Strategy: validation
Validate before calling
from supervision.detection.core import Detections
def ids_ready(preds: Detections, tgts: Detections) -> bool:
"""MAR needs class_id whenever targets are non-empty."""
if len(tgts) == 0:
return True
return preds.class_id is not None and tgts.class_id is not None Type guard
from supervision.detection.core import Detections
from typing import Optional
import numpy as np
def has_class_id(dets: Detections) -> bool:
"""True when Detections carries a non-None class_id array."""
return dets.class_id is not None Prevention
- Always pass class_id when constructing Detections for evaluation
- For class-agnostic runs assign zeros as class_id on both sides
- Check class_id is not None on both sides before update() when targets exist
When it happens
Trigger: Building sv.Detections without class_id (e.g. detector output parsed to only xyxy+confidence); a model connector that leaves class_id None; class_id set on predictions but omitted when constructing target Detections from label files; calling compute() after update() with class-less detections on any annotated image.
Common situations: Class-agnostic single-class setups where developers assume ids are unnecessary; hand-rolled COCO/VOC parsers that forget the class_id field; using a face/person detector whose output connector drops class ids; mixing data sources where one side populates class_id and the other does not.
Related errors
- The number of predictions ({len(predictions)}) and targets (
- MeanAverageRecall metric requires `confidence` on prediction
- Invalid metric target: {self._metric_target}
- MeanAverageRecall with `MetricTarget.MASKS` requires detecti
- The number of predictions ({len(predictions)}) and targets (
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/99d0d23abedad051.
Report an issue: GitHub.