roboflow/supervision · error · ValueError
MeanAveragePrecision with `MetricTarget.ORIENTED_BOUNDING_BO
Error message
MeanAveragePrecision with `MetricTarget.ORIENTED_BOUNDING_BOXES` requires `{ORIENTED_BOX_COORDINATES}` in `data` on both predictions and targets. What it means
For MeanAveragePrecision with metric_target=MetricTarget.ORIENTED_BOUNDING_BOXES, oriented-box coordinates are not a first-class Detections field — they live in the data dict under the ORIENTED_BOX_COORDINATES key ('obb_boxes'-style constant) as an (N, 4, 2) corner array. This ValueError fires in _detections_content when a non-empty Detections lacks that data key, and names the exact constant required.
Source
Thrown at src/supervision/metrics/mean_average_precision.py:1478
return self
def _detections_content(self, detections: Detections) -> npt.NDArray[Any] | None:
"""Return per-detection masks or oriented boxes for the metric target,
or `None` for the box target and for empty detections."""
if self._metric_target == MetricTarget.BOXES or len(detections) == 0:
return None
if self._metric_target == MetricTarget.MASKS:
if detections.mask is None:
raise ValueError(
"MeanAveragePrecision with `MetricTarget.MASKS` requires"
" masks on both predictions and targets."
)
return np.asarray(detections.mask).astype(bool)
if self._metric_target == MetricTarget.ORIENTED_BOUNDING_BOXES:
obb = detections.data.get(ORIENTED_BOX_COORDINATES)
if obb is None:
raise ValueError(
"MeanAveragePrecision with"
" `MetricTarget.ORIENTED_BOUNDING_BOXES` requires"
f" `{ORIENTED_BOX_COORDINATES}` in `data` on both"
" predictions and targets."
)
return np.asarray(obb, dtype=np.float32).reshape(-1, 4, 2)
raise ValueError(f"Invalid metric target: {self._metric_target}")
def _content_area(
self, xywh: list[float], content: npt.NDArray[Any] | None, idx: int
) -> float:
"""Compute the default annotation area for the metric target: bbox area
for boxes, pixel count for masks, polygon area for oriented boxes."""
if content is None:
return float(xywh[2] * xywh[3])
if self._metric_target == MetricTarget.MASKS:
return float(np.count_nonzero(content[idx]))
x, y = content[idx, :, 0], content[idx, :, 1]View on GitHub (pinned to 7f254d9784)
Solutions
- Attach oriented boxes on both sides: detections.data[ORIENTED_BOX_COORDINATES] = np.array corners of shape (N, 4, 2), importing the constant from supervision.config (print it from the error message if unsure of the exact name)
- Use an OBB-aware connector (e.g. from_ultralytics on an OBB model) that populates the data field
- If you only have axis-aligned boxes, fall back to MetricTarget.BOXES
- Validate before update: check the key exists in .data for every non-empty Detections
Example fix
# before
map_ = sv.MeanAveragePrecision(metric_target=sv.MetricTarget.ORIENTED_BOUNDING_BOXES)
preds = sv.Detections(xyxy=boxes, class_id=ids, confidence=confs) # no obb data
map_.update(preds, targets)
# after
from supervision.config import ORIENTED_BOX_COORDINATES
preds = sv.Detections(xyxy=boxes, class_id=ids, confidence=confs,
data={ORIENTED_BOX_COORDINATES: pred_corners}) # (N,4,2)
targets = sv.Detections(xyxy=gt_boxes, class_id=gt_ids,
data={ORIENTED_BOX_COORDINATES: gt_corners})
map_.update(preds, targets) Defensive patterns
Strategy: validation
Validate before calling
from supervision.config import ORIENTED_BOX_COORDINATES
def obb_ok(dets) -> bool:
"""OBB-target precondition: empty or carries the obb data key."""
return len(dets) == 0 or ORIENTED_BOX_COORDINATES in dets.data
assert obb_ok(preds) and obb_ok(targets) Type guard
import numpy as np
from supervision.config import ORIENTED_BOX_COORDINATES
from supervision.detection.core import Detections
def has_obb_data(dets: Detections) -> bool:
"""True when Detections carries an (N, 4, 2) corner array under the obb key."""
obb = dets.data.get(ORIENTED_BOX_COORDINATES)
return obb is not None and np.asarray(obb).ndim in (2, 3) Prevention
- Import ORIENTED_BOX_COORDINATES from supervision.config; never hand-type the key
- Store corner arrays shaped (N, 4, 2) on both predictions and targets
- Use an OBB connector for rotated-detector outputs
When it happens
Trigger: Setting metric_target=ORIENTED_BOUNDING_BOXES but building Detections with only xyxy (rotated-box data never attached); using a connector that stores OBB under a custom/differently named data key; predictions carry data but targets (or vice versa) were built without it; renaming or hand-rolling the constant string instead of importing it from supervision.config.
Common situations: Evaluating OBB models (rotated YOLO, aerial/sar/ship datasets, DOTA-style) where predictions and annotations must both be converted to corner arrays; migrating between supervision versions where the data-key constant changed; partial pipelines that populate OBB on inference output but not on parsed GT labels.
Related errors
- Invalid metric target: {self._metric_target}
- results must be a list
- Results do not correspond to current coco set
- The number of predictions ({len(predictions)}) and targets (
- The number of predictions ({total_images_predictions}) and t
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/32a1eaf3b4ff2711.
Report an issue: GitHub.