{"record":{"id":"3a412d99cd9156d5","repo":"roboflow/supervision","slug":"mask-must-be-boolean","errorCode":null,"errorMessage":"mask must be boolean","messagePattern":"mask must be boolean","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/supervision/detection/utils/masks.py","lineNumber":452,"sourceCode":"               [0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],\n               [0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],\n               [0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0],\n               [0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0],\n               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])\n\n        ```\n\n        The nearby 2x2 block at columns 6-7 is kept because its edge distance\n        is within 3 pixels. The distant block at columns 9-10 is removed.\n    \"\"\"  # noqa E501 // docs\n    if mask.dtype != bool:\n        raise TypeError(\"mask must be boolean\")\n\n    height, width = mask.shape\n    if not np.any(mask):\n        return cast(npt.NDArray[np.bool_], mask.copy())\n\n    image = cast(npt.NDArray[np.uint8], mask.astype(np.uint8))\n    components = cv2.connectedComponentsWithStats(image, connectivity=connectivity)\n    num_labels = int(components[0])\n    labels = cast(npt.NDArray[np.int32], components[1])\n    stats = cast(npt.NDArray[np.int32], components[2])\n    centroids = cast(npt.NDArray[np.float64], components[3])\n\n    if num_labels <= 1:\n        return cast(npt.NDArray[np.bool_], mask.copy())\n\n    areas = stats[1:, cv2.CC_STAT_AREA]\n    max_area = int(areas.max())\n    candidates = 1 + np.flatnonzero(areas == max_area)","sourceCodeStart":434,"sourceCodeEnd":470,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/detection/utils/masks.py#L434-L470","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["Convert before calling: mask.astype(bool).","Normalize masks once at the boundary of your pipeline (right after model inference) to bool.","For 0/255 images, threshold: mask = img > 127."],"exampleFix":"# before\n cleaned = filter_non_zero_mask_areas(mask=raw_uint8_mask, ...)\n\n# after\n cleaned = filter_non_zero_mask_areas(mask=raw_uint8_mask.astype(bool), ...)","handlingStrategy":"type-guard","validationCode":"if mask.dtype != np.bool_:\n    mask = mask.astype(bool)","typeGuard":"def is_bool_mask(mask: npt.NDArray) -> bool:\n    return mask.dtype == np.bool_","tryCatchPattern":"try:\n    result = filter_non_zero_mask_areas(mask=mask, ...)\nexcept TypeError as e:\n    raise TypeError(f\"Mask dtype {mask.dtype} not supported: {e}\") from e","preventionTips":["Convert uint8/float masks to bool once, right after model inference.","Use mask > 0 (or > 127 for 0/255 images) instead of astype for thresholds.","Standardize on boolean masks across your whole supervision pipeline."],"tags":["masks","dtype","typeerror","opencv"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}