roboflow/supervision · error · ValueError

xyxy must have shape (N, 4), where N matches the number of R

Error message

xyxy must have shape (N, 4), where N matches the number of RLEs.

What it means

Raised by CompactMask.from_coco_rle when the xyxy bounding-box array's shape is not exactly (N, 4) where N equals len(rles). Each RLE must be paired with one bounding box that defines its crop region; a mismatched or wrongly shaped xyxy makes the pairing impossible.

Source

Thrown at src/supervision/detection/compact_mask.py:793

            >>> cm.shape
            (1, 4, 4)
            >>> cm.area.tolist()
            [4]

            ```
        """
        img_h, img_w = (int(image_shape[0]), int(image_shape[1]))
        if img_h <= 0 or img_w <= 0:
            raise ValueError("image_shape must contain positive height and width.")
        if img_h > _MAX_IMAGE_DIMENSION or img_w > _MAX_IMAGE_DIMENSION:
            raise ValueError(
                f"image_shape {(img_h, img_w)} exceeds the maximum allowed dimension "
                f"of {_MAX_IMAGE_DIMENSION} pixels per side."
            )

        xyxy_arr = np.asarray(xyxy)
        if xyxy_arr.shape != (len(rles), 4):
            raise ValueError(
                "xyxy must have shape (N, 4), where N matches the number of RLEs."
            )

        if len(rles) == 0:
            return cls(
                [],
                np.empty((0, 2), dtype=np.int32),
                np.empty((0, 2), dtype=np.int32),
                (img_h, img_w),
            )

        crop_rles: list[npt.NDArray[np.int32]] = []
        crop_shapes_list: list[tuple[int, int]] = []
        offsets_list: list[tuple[int, int]] = []

        for mask_idx, rle in enumerate(rles):
            if not isinstance(rle, Mapping):
                raise ValueError("Each RLE payload must be a mapping.")

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Ensure one box per RLE: len(xyxy) == len(rles), and each row is [x1, y1, x2, y2].
  2. Convert COCO bbox xywh -> xyxy before the call: xyxy = xywh.copy(); xyxy[:, 2:] += xyxy[:, :2].
  3. For a single mask use np.array([[x1, y1, x2, y2]]) (leading bracket keeps shape (1, 4)).

Example fix

# before
xyxy = np.array(anns["bbox"])  # xywh, and count mismatch

# after
xywh = np.array([a["bbox"]] * 0 + [a["bbox"] for a in anns])
xyxy = np.array([a["bbox"] for a in anns], dtype=np.float32)
xyxy[:, 2:] += xyxy[:, :2]
Defensive patterns

Strategy: validation

Validate before calling

import numpy as np
xyxy = np.asarray(xyxy, dtype=np.float32)
assert xyxy.shape == (len(rles), 4), f"need ({len(rles)}, 4), got {xyxy.shape}"

Type guard

def is_valid_xyxy_for(xyxy, rles) -> bool:
    xyxy = np.asarray(xyxy)
    return xyxy.ndim == 2 and xyxy.shape == (len(rles), 4)

Prevention

When it happens

Trigger: Passing 3 boxes with 5 RLEs; passing xyxy of shape (N, 5) (e.g. xywh instead of xyxy); passing a flat array of shape (4,) for a single mask instead of (1, 4).

Common situations: COCO annotations store [x, y, width, height] — passing bbox unconverted produces (N, 4) but semantically wrong, while filtering rles without filtering xyxy (or vice versa) produces the N mismatch; forgetting xyxy=np.array([[...]]) nesting for one mask.

Related errors


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