{"record":{"id":"0a910258ad0ab8b9","repo":"roboflow/supervision","slug":"input-mask-cannot-be-empty","errorCode":null,"errorMessage":"Input mask cannot be empty","messagePattern":"Input mask cannot be empty","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/detection/utils/converters.py","lineNumber":794,"sourceCode":"        ...     [False, True,  True,  False],\n        ...     [False, False, False, False],\n        ... ])\n        >>> rle = sv.mask_to_rle(mask)\n        >>> [int(x) for x in rle]\n        [5, 2, 2, 2, 5]\n\n        >>> sv.mask_to_rle(mask, compressed=True)\n        '52203'\n\n        ```\n\n    ![mask_to_rle](https://media.roboflow.com/supervision-docs/\n    mask-to-rle.png){ align=center width=\"800\" }\n    \"\"\"\n    if mask.ndim != 2:\n        raise ValueError(\"Input mask must be 2D\")\n    if mask.size == 0:\n        raise ValueError(\"Input mask cannot be empty\")\n\n    counts: list[int] = cast(list[int], _mask_to_rle_counts(mask).tolist())\n    if compressed:\n        return _base48_encode(_delta_encode(counts))\n    return counts\n\n\ndef polygon_to_xyxy(polygon: npt.NDArray[np.number]) -> npt.NDArray[np.number]:\n    \"\"\"\n    Converts a polygon represented by a NumPy array into a bounding box.\n\n    Args:\n        polygon: A polygon represented by a NumPy array of shape `(N, 2)`,\n            containing the `x`, `y` coordinates of the points.\n\n    Returns:\n        A 1D NumPy array containing the bounding box\n            `(x_min, y_min, x_max, y_max)` of the input polygon.","sourceCodeStart":776,"sourceCodeEnd":812,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/detection/utils/converters.py#L776-L812","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Skip empty masks: if mask.size == 0: continue before encoding.","Fix the upstream crop logic — validate bounding boxes are within the frame and non-degenerate before slicing.","Check len(detections) > 0 before iterating its mask array."],"exampleFix":"# before\n rle = sv.mask_to_rle(cropped_mask)\n\n# after\n if cropped_mask.size == 0:\n     continue\n rle = sv.mask_to_rle(cropped_mask)","handlingStrategy":"validation","validationCode":"if mask.ndim != 2:\n    mask = np.squeeze(mask)\nif mask.size == 0:\n    return None  # nothing to encode","typeGuard":"def is_encodable_mask(mask: npt.NDArray) -> bool:\n    return mask.ndim == 2 and mask.size > 0","tryCatchPattern":null,"preventionTips":["Skip empty crops before encoding.","Validate bounding boxes are in-frame and non-degenerate before slicing masks.","Check len(detections) before iterating per-detection masks."],"tags":["rle","mask","empty-input","validation"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}