roboflow/supervision · error · ValueError

Input mask cannot be empty

Error message

Input mask cannot be empty

What it means

mask_to_rle refuses masks with size 0 (e.g. shape (0, 0) or (0, W)) because an empty mask has no pixels to describe and the RLE convention (alternating background/foreground runs starting with background) cannot represent it meaningfully. This fires after the 2D check, so only well-formed but empty arrays reach it.

Source

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

        ...     [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:
        A 1D NumPy array containing the bounding box
            `(x_min, y_min, x_max, y_max)` of the input polygon.

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Skip empty masks: if mask.size == 0: continue before encoding.
  2. Fix the upstream crop logic — validate bounding boxes are within the frame and non-degenerate before slicing.
  3. Check len(detections) > 0 before iterating its mask array.

Example fix

# before
 rle = sv.mask_to_rle(cropped_mask)

# after
 if cropped_mask.size == 0:
     continue
 rle = sv.mask_to_rle(cropped_mask)
Defensive patterns

Strategy: validation

Validate before calling

if mask.ndim != 2:
    mask = np.squeeze(mask)
if mask.size == 0:
    return None  # nothing to encode

Type guard

def is_encodable_mask(mask: npt.NDArray) -> bool:
    return mask.ndim == 2 and mask.size > 0

Prevention

When it happens

Trigger: Slicing a mask region to nothing (mask[0:0, :]) before encoding; detections with an empty mask array of shape (0, H, W) where a per-detection loop still feeds one slice; upstream code producing zero-sized crops for out-of-frame boxes.

Common situations: Cropping masks with clipped/invalid bounding boxes that yield zero rows or columns; processing empty frames after filtering all detections but still calling encode on an empty slice.

Related errors


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