roboflow/supervision · error · ValueError

Bounding boxes must be shaped (N, 4)

Error message

Bounding boxes must be shaped (N, 4)

What it means

Raised by get_bbox_size_category() when the input bounding-box array is not 2-D with exactly 4 columns (xyxy format). The function computes width*height per row to bucket boxes into SMALL/MEDIUM/LARGE, so a malformed shape would corrupt the per-box area vector. It validates shape before any arithmetic.

Source

Thrown at src/supervision/metrics/utils/object_size.py:117

        the enum values of ObjectSizeCategory. Shaped (N,).

    Example:
        ```pycon
        >>> import numpy as np
        >>> from supervision.metrics.utils.object_size import get_bbox_size_category
        >>> xyxy = np.array([
        ...     [0, 0, 31, 31],    # 961 (Small)
        ...     [0, 0, 32, 32],    # 1024 (Medium)
        ...     [0, 0, 95, 95],    # 9025 (Medium)
        ...     [0, 0, 96, 96]     # 9216 (Large)
        ... ])
        >>> get_bbox_size_category(xyxy)
        array([1, 2, 2, 3])

        ```
    """
    if len(xyxy.shape) != 2 or xyxy.shape[1] != 4:
        raise ValueError("Bounding boxes must be shaped (N, 4)")

    width = xyxy[:, 2] - xyxy[:, 0]
    height = xyxy[:, 3] - xyxy[:, 1]
    areas = width * height

    result = np.full(areas.shape, ObjectSizeCategory.ANY.value)
    SM, LG = SIZE_THRESHOLDS
    result[areas < SM] = ObjectSizeCategory.SMALL.value
    result[(areas >= SM) & (areas < LG)] = ObjectSizeCategory.MEDIUM.value
    result[areas >= LG] = ObjectSizeCategory.LARGE.value
    return result


def get_area_size_category(
    areas: npt.NDArray[np.number],
) -> npt.NDArray[np.int_]:
    """Get object size categories from per-detection pixel areas.

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Reshape input to (N, 4): np.asarray(boxes).reshape(-1, 4) when it is a flat list of boxes
  2. If you have oriented boxes, use get_obb_size_category instead
  3. Add a shape assert in your pipeline: assert boxes.ndim == 2 and boxes.shape[1] == 4

Example fix

# before
size = get_bbox_size_category(np.array([0, 0, 31, 31]))  # 1-D

# after
size = get_bbox_size_category(np.array([[0, 0, 31, 31]]))  # (1, 4)
Defensive patterns

Strategy: validation

Validate before calling

boxes = np.asarray(boxes)
if boxes.ndim != 2 or boxes.shape[1] != 4:
    boxes = boxes.reshape(-1, 4)
cats = get_bbox_size_category(boxes)

Type guard

import numpy as np

def is_valid_xyxy(arr: np.ndarray) -> bool:
    """True when arr is (N, 4) suitable for bbox size categorization."""
    return arr.ndim == 2 and arr.shape[1] == 4

Try / catch

try:
    cats = get_bbox_size_category(boxes)
except ValueError as e:
    if 'shaped (N, 4)' in str(e):
        cats = get_bbox_size_category(boxes.reshape(-1, 4))
    else:
        raise

Prevention

When it happens

Trigger: Calling get_bbox_size_category with a (N,5) array, a flat (4,) vector, a (N,4,2) OBB array, or an empty (0,) array.

Common situations: Passing xyxyxyxy (oriented box) coordinates by mistake; passing a single box [x1,y1,x2,y2] without wrapping in a 2-D array; slicing errors that drop a dimension; passing mask or polygon data.

Related errors


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