roboflow/supervision · error · ValueError

Input mask must be 2D

Error message

Input mask must be 2D

What it means

mask_to_rle encodes a single 2D binary mask (H x W) into alternating run counts; a 3D array (e.g. a batch of masks with shape (N, H, W)) or a 1D vector has no well-defined scan order for a single mask, so ndim != 2 raises immediately.

Source

Thrown at src/supervision/detection/utils/converters.py:792

        ...     [False, False, False, False],
        ...     [False, True,  True,  False],
        ...     [False, True,  True,  False],
        ...     [False, False, False, False],
        ... ])
        >>> rle = sv.mask_to_rle(mask)
        >>> [int(x) for x in rle]
        [5, 2, 2, 2, 5]

        >>> sv.mask_to_rle(mask, compressed=True)
        '52203'

        ```

    ![mask_to_rle](https://media.roboflow.com/supervision-docs/
    mask-to-rle.png){ align=center width="800" }
    """
    if mask.ndim != 2:
        raise ValueError("Input mask must be 2D")
    if mask.size == 0:
        raise ValueError("Input mask cannot be empty")

    counts: list[int] = cast(list[int], _mask_to_rle_counts(mask).tolist())
    if compressed:
        return _base48_encode(_delta_encode(counts))
    return counts


def polygon_to_xyxy(polygon: npt.NDArray[np.number]) -> npt.NDArray[np.number]:
    """
    Converts a polygon represented by a NumPy array into a bounding box.

    Args:
        polygon: A polygon represented by a NumPy array of shape `(N, 2)`,
            containing the `x`, `y` coordinates of the points.

    Returns:

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Index one mask from the batch: mask_to_rle(detections.mask[i]).
  2. Squeeze spurious dims right before the call: np.squeeze(mask) then assert .ndim == 2.
  3. For a (H, W, 1) tensor conversion, use [..., 0].

Example fix

# before
 rles = [sv.mask_to_rle(m) for m in detections.mask]

# after
 rles = [sv.mask_to_rle(detections.mask[i]) for i in range(len(detections))]
Defensive patterns

Strategy: type-guard

Validate before calling

assert mask.ndim == 2, f"expected 2D mask, got shape {mask.shape}"

Type guard

def is_single_2d_mask(mask: npt.NDArray) -> bool:
    return mask.ndim == 2

Prevention

When it happens

Trigger: Passing detections.mask (shape (N, H, W)) directly instead of one slice detections.mask[i]; passing a single row/column vector; passing a mask with a trailing channel dimension (H, W, 1) from a tensor conversion.

Common situations: Iterating batches and forgetting to index; converting torch tensors with .numpy() that keep a batch or channel dim; feeding model output directly.

Related errors


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