roboflow/supervision · error · ValueError
xyxy must be a 2D np.ndarray with shape {expected_shape}, bu
Error message
xyxy must be a 2D np.ndarray with shape {expected_shape}, but got shape {actual_shape} What it means
Raised by supervision.validators._validate_xyxy when the xyxy argument to Detections is not a 2D NumPy array with exactly 4 columns. xyxy is the canonical box container for Detections and must have shape (N, 4) as (xmin, ymin, xmax, ymax) per row.
Source
Thrown at src/supervision/validators/__init__.py:22
from deprecate import deprecated, void # type: ignore[import-untyped,unused-ignore]
from supervision.detection.compact_mask import CompactMask
from supervision.utils.internal import warn_deprecated
def _validate_xyxy(xyxy: Any) -> None:
"""Validate that xyxy is a 2D np.ndarray with shape (N, 4).
```pycon
>>> _validate_xyxy(np.array([[0, 0, 1, 1], [1, 1, 2, 2]]))
```
"""
expected_shape = "(_, 4)"
actual_shape = str(getattr(xyxy, "shape", None))
is_valid = isinstance(xyxy, np.ndarray) and xyxy.ndim == 2 and xyxy.shape[1] == 4
if not is_valid:
raise ValueError(
f"xyxy must be a 2D np.ndarray with shape {expected_shape}, but got shape "
f"{actual_shape}"
)
@deprecated( # type: ignore[untyped-decorator]
target=_validate_xyxy,
deprecated_in="0.29.0",
remove_in="0.32.0",
)
def validate_xyxy(xyxy: Any) -> None:
void(xyxy)
def _validate_mask(mask: Any, n: int) -> None:
if mask is None:
return
View on GitHub (pinned to 7f254d9784)
Solutions
- Convert and reshape: Detections(xyxy=boxes.reshape(-1, 4)) where boxes is a NumPy array.
- Convert xywh to xyxy with supervision.detection.utils.xywh_to_xyxy before constructing Detections.
- For a single box use np.array([[xmin, ymin, xmax, ymax]]) with explicit outer brackets.
- Prefer model connectors (Detections.from_ultralytics, etc.) which return correctly shaped arrays.
Example fix
# before boxes = np.array([100, 100, 200, 200]) dets = Detections(xyxy=boxes) # 1D -> ValueError # after boxes = np.array([[100, 100, 200, 200]]) dets = Detections(xyxy=boxes)
Defensive patterns
Strategy: type-guard
Validate before calling
xyxy = np.asarray(xyxy, dtype=np.float32).reshape(-1, 4) dets = Detections(xyxy=xyxy)
Type guard
def is_valid_xyxy(xyxy: Any) -> bool:
return (
isinstance(xyxy, np.ndarray)
and xyxy.ndim == 2
and xyxy.shape[1] == 4
) Prevention
- Wrap raw model output with np.asarray(...).reshape(-1, 4) before Detections.
- Use xywh_to_xyxy when the source format is center-based.
- Prefer built-in from_* connectors over manual construction.
When it happens
Trigger: Constructing Detections(xyxy=np.array([0, 0, 1, 1])) (1D), Detections(xyxy=np.array([[0, 0, 1]])) (3 columns), or passing a Python list/None instead of np.ndarray.
Common situations: Forgetting np.array()/np.asarray() on raw model output; hand-building Detections from a single box instead of a batch; passing xywh (4 values but wrong order/semantics is fine shape-wise, passing (N, 5) with confidence appended is not); slicing arrays incorrectly so they collapse to 1D.
Related errors
- class_id must be a 1D np.ndarray with shape {expected_shape}
- confidence must be a 1D np.ndarray with shape {expected_shap
- tracker_id must be a 1D np.ndarray with shape {expected_shap
- Detections must have class_id attribute.
- Both Detections should have exactly 1 detected object.
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/0f1cd330f3f30fd7.
Report an issue: GitHub.