{"record":{"id":"7334da8676b8626c","repo":"roboflow/supervision","slug":"coordinate-convention-must-be-inclusive-or-excl","errorCode":null,"errorMessage":"coordinate_convention must be 'inclusive' or 'exclusive', got {coordinate_convention}.","messagePattern":"coordinate_convention must be 'inclusive' or 'exclusive', got (.+?)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/detection/utils/converters.py","lineNumber":280,"sourceCode":"        return np.zeros((n, 4), dtype=int)\n\n    # Reduce the mask stack to per-row / per-column occupancy, then read the\n    # tight bounds straight off those 1D profiles instead of scanning every\n    # pixel of every mask with `np.where`.\n    rows_any = cast(npt.NDArray[np.bool_], masks.any(axis=2))  # (N, H)\n    cols_any = cast(npt.NDArray[np.bool_], masks.any(axis=1))  # (N, W)\n\n    x_min = cols_any.argmax(axis=1)\n    y_min = rows_any.argmax(axis=1)\n\n    if coordinate_convention == \"inclusive\":\n        x_max = width - 1 - cols_any[:, ::-1].argmax(axis=1)\n        y_max = height - 1 - rows_any[:, ::-1].argmax(axis=1)\n    elif coordinate_convention == \"exclusive\":\n        x_max = width - cols_any[:, ::-1].argmax(axis=1)\n        y_max = height - rows_any[:, ::-1].argmax(axis=1)\n    else:\n        raise ValueError(\n            \"coordinate_convention must be 'inclusive' or 'exclusive', \"\n            f\"got {coordinate_convention!r}.\"\n        )\n\n    xyxy = np.stack((x_min, y_min, x_max, y_max), axis=1).astype(int)\n    # Empty masks have no bounds; keep the original all-zeros box for them.\n    xyxy[~rows_any.any(axis=1)] = 0\n    return xyxy\n\n\ndef xyxy_to_mask(\n    boxes: npt.NDArray[np.number],\n    resolution_wh: tuple[int, int],\n    coordinate_convention: CoordinateConvention = \"inclusive\",\n) -> npt.NDArray[np.bool_]:\n    \"\"\"\n    Converts a 2D `np.ndarray` of bounding boxes into a 3D `np.ndarray` of bool masks.\n","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/detection/utils/converters.py#L262-L298","documentation":"masks_to_xyxy_bounds converts boolean masks to bounding boxes under one of two conventions: 'inclusive' (x_max is the last foreground column, COCO-style) or 'exclusive' (x_max is one past the last column, slice-friendly). Any other string reaches the else branch and raises, because the two conventions produce different coordinates and the caller must choose explicitly.","triggerScenarios":"Passing coordinate_convention='Inclusive' (capitalized), 'incl', or omitting it where no default exists in the code path; forwarding a config value with a typo.","commonSituations":"Bridging COCO annotations (inclusive) with NumPy slicing (exclusive) and guessing the keyword; case-sensitive config values; renaming the parameter in older code.","solutions":["Use exactly 'inclusive' or 'exclusive' (lowercase strings).","Pick 'exclusive' if you will use the bounds as slice end indices, 'inclusive' if you compare against pixel coordinates.","Normalize any config-sourced value with .strip().lower()."],"exampleFix":"# before\n xyxy = sv.masks_to_xyxy_bounds(masks=masks, coordinate_convention=\"Inclusive\")\n\n# after\n xyxy = sv.masks_to_xyxy_bounds(masks=masks, coordinate_convention=\"inclusive\")","handlingStrategy":"validation","validationCode":"coordinate_convention = coordinate_convention.strip().lower()\nif coordinate_convention not in (\"inclusive\", \"exclusive\"):\n    raise ValueError(f\"bad convention {coordinate_convention!r}\")","typeGuard":"def is_valid_convention(value: str) -> bool:\n    return value.strip().lower() in (\"inclusive\", \"exclusive\")","tryCatchPattern":null,"preventionTips":["Use 'exclusive' when bounds feed NumPy slices; 'inclusive' for pixel-coordinate math.","Keep a single CONVENTION constant shared across encode/decode calls.","Normalize config strings before passing."],"tags":["converters","masks","convention","validation"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}