roboflow/supervision · error · ValueError
MeanAverageRecall with `MetricTarget.MASKS` requires detecti
Error message
MeanAverageRecall with `MetricTarget.MASKS` requires detections to include masks.
What it means
When MeanAverageRecall is configured with metric_target=MetricTarget.MASKS, it must extract a boolean mask per detection. This ValueError fires in _detections_content when detections.mask is None while the Detections object still contains >=1 detection. Empty Detections are tolerated (an empty mask placeholder is returned), but any non-empty detections without masks cannot be evaluated and are rejected.
Source
Thrown at src/supervision/metrics/mean_average_recall.py:687
return result_recall
def _detections_content(
self, detections: Detections
) -> npt.NDArray[Any] | CompactMask:
"""Return boxes, masks or oriented bounding boxes from detections.
For the mask target this may return a
:class:`~supervision.detection.compact_mask.CompactMask` rather than a
dense boolean array when the detections carry compact masks.
"""
if self._metric_target == MetricTarget.BOXES:
return cast(npt.NDArray[Any], detections.xyxy)
if self._metric_target == MetricTarget.MASKS:
if detections.mask is not None:
# detections.mask is NDArray[bool] | CompactMask; return as-is.
return detections.mask
if len(detections) > 0:
raise ValueError(
"MeanAverageRecall with `MetricTarget.MASKS` requires "
"detections to include masks."
)
return self._make_empty_content()
if self._metric_target == MetricTarget.ORIENTED_BOUNDING_BOXES:
obb = detections.data.get(ORIENTED_BOX_COORDINATES)
if obb is not None and len(obb) > 0:
result_obb: npt.NDArray[np.float32] = np.array(obb, dtype=np.float32)
return result_obb
return self._make_empty_content()
raise ValueError(f"Invalid metric target: {self._metric_target}")
def _make_empty_content(self) -> npt.NDArray[Any]:
if self._metric_target == MetricTarget.BOXES:
empty_boxes: npt.NDArray[np.float32] = np.empty((0, 4), dtype=np.float32)
return empty_boxes
if self._metric_target == MetricTarget.MASKS:View on GitHub (pinned to 7f254d9784)
Solutions
- If evaluating boxes, keep the default metric_target=MetricTarget.BOXES
- If masks are required, feed detections that carry masks: use a segmentation model and the appropriate connector (e.g. YOLO-Seg via from_ultralytics) so detections.mask is populated
- When hand-building Detections, pass mask=np.array([H,W,N] boolean) explicitly for both predictions and targets
- Verify per-image before update: if metric target is MASKS, assert detections.mask is not None or detections.is_empty()
Example fix
# before
mar = sv.MeanAverageRecall(metric_target=sv.MetricTarget.MASKS)
preds = sv.Detections(xyxy=boxes, confidence=confs, class_id=ids) # no mask
mar.update(preds, targets)
# after
mar = sv.MeanAverageRecall(metric_target=sv.MetricTarget.MASKS)
preds = sv.Detections(xyxy=boxes, confidence=confs, class_id=ids,
mask=pred_masks) # (N,H,W) bool
targets = sv.Detections(xyxy=gt_boxes, class_id=gt_ids, mask=gt_masks)
mar.update(preds, targets) Defensive patterns
Strategy: validation
Validate before calling
from supervision.detection.core import Detections
def masks_ready(dets: Detections) -> bool:
"""Non-empty Detections must carry masks for MASKS-target evaluation."""
return dets.is_empty() or dets.mask is not None Type guard
from supervision.detection.core import Detections
def has_masks(dets: Detections) -> bool:
"""True when Detections is empty or carries a mask array."""
return dets.mask is not None or len(dets) == 0 Prevention
- Use a segmentation model and its connector so .mask is populated end to end
- Keep metric_target consistent with the model task (detect vs segment)
- Set a pipeline precondition: MASKS target => .mask is not None on every non-empty Detections
When it happens
Trigger: Constructing MeanAverageRecall(metric_target=MetricTarget.MASKS) and calling update()/compute() with Detections built from box-only model outputs (sv.Detections(xyxy=..., class_id=...) with no mask= kwarg); using a detector connector (e.g. from_ultralytics on a detection model) instead of a segmentation connector; masks present on predictions but missing on targets (error names whichever side lacks them).
Common situations: Running a YOLO detect (not segment) checkpoint with the MASKS metric target; forgetting to pass mask= when hand-building Detections from postprocessed arrays; mixing pipelines where inference adds masks but GT loading (COCO/labels) drops them; migrating from BOXES default to MASKS without regenerating targets.
Related errors
- MeanAveragePrecision with `MetricTarget.MASKS` requires mask
- All KeyPoints must have the same number of keypoints per ske
- Invalid metric target: {self._metric_target}
- The number of predictions ({len(predictions)}) and targets (
- MeanAverageRecall metric requires `class_id` on both predict
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/929272a1c089743e.
Report an issue: GitHub.