roboflow/supervision · error · TypeError

mask must be boolean

Error message

mask must be boolean

What it means

The mask-cleanup helper (filter_small_components / keep-nearby-components style API in detection/utils/masks.py) is a TypeError raised when mask.dtype is not bool. Internally the mask is treated as a boolean bitmap for connected-component analysis; uint8/float arrays would change semantics (any nonzero counts), so the dtype is enforced strictly.

Source

Thrown at src/supervision/detection/utils/masks.py:452

               [0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0],
               [0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

        ```

        The nearby 2x2 block at columns 6-7 is kept because its edge distance
        is within 3 pixels. The distant block at columns 9-10 is removed.
    """  # noqa E501 // docs
    if mask.dtype != bool:
        raise TypeError("mask must be boolean")

    height, width = mask.shape
    if not np.any(mask):
        return cast(npt.NDArray[np.bool_], mask.copy())

    image = cast(npt.NDArray[np.uint8], mask.astype(np.uint8))
    components = cv2.connectedComponentsWithStats(image, connectivity=connectivity)
    num_labels = int(components[0])
    labels = cast(npt.NDArray[np.int32], components[1])
    stats = cast(npt.NDArray[np.int32], components[2])
    centroids = cast(npt.NDArray[np.float64], components[3])

    if num_labels <= 1:
        return cast(npt.NDArray[np.bool_], mask.copy())

    areas = stats[1:, cv2.CC_STAT_AREA]
    max_area = int(areas.max())
    candidates = 1 + np.flatnonzero(areas == max_area)

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Convert before calling: mask.astype(bool).
  2. Normalize masks once at the boundary of your pipeline (right after model inference) to bool.
  3. For 0/255 images, threshold: mask = img > 127.

Example fix

# before
 cleaned = filter_non_zero_mask_areas(mask=raw_uint8_mask, ...)

# after
 cleaned = filter_non_zero_mask_areas(mask=raw_uint8_mask.astype(bool), ...)
Defensive patterns

Strategy: type-guard

Validate before calling

if mask.dtype != np.bool_:
    mask = mask.astype(bool)

Type guard

def is_bool_mask(mask: npt.NDArray) -> bool:
    return mask.dtype == np.bool_

Try / catch

try:
    result = filter_non_zero_mask_areas(mask=mask, ...)
except TypeError as e:
    raise TypeError(f"Mask dtype {mask.dtype} not supported: {e}") from e

Prevention

When it happens

Trigger: Passing a 0/255 uint8 mask loaded from cv2.imread or a model's logits/float array without converting: calling the cleanup function with mask.astype(np.uint8) output straight from an inference pipeline.

Common situations: Masks from SAM/YOLO seg branches stored as uint8; masks saved/loaded as PNG images; mixing supervision boolean-mask APIs with OpenCV convention (0/255).

Related errors


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