{"record":{"id":"94730b8ec5b1830a","repo":"roboflow/supervision","slug":"only-4-and-8-connectivity-are-supported","errorCode":null,"errorMessage":"Only 4- and 8-connectivity are supported","messagePattern":"Only 4- and 8-connectivity are supported","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/_cv2/_components.py","lineNumber":24,"sourceCode":"\nimport numpy as np\nimport numpy.typing as npt\n\n\ndef _validate_binary_image(image: npt.NDArray[Any]) -> npt.NDArray[np.bool_]:\n    \"\"\"Validate and normalize a two-dimensional component image.\"\"\"\n    values = np.asarray(image)\n    if values.ndim != 2:\n        raise ValueError(\"Connected-component input must be a two-dimensional image\")\n    return cast(npt.NDArray[np.bool_], values != 0)\n\n\ndef _label(\n    image: npt.NDArray[Any], connectivity: int\n) -> tuple[int, npt.NDArray[np.int32]]:\n    \"\"\"Label foreground pixels with the requested four- or eight-way topology.\"\"\"\n    if connectivity not in (4, 8):\n        raise ValueError(\"Only 4- and 8-connectivity are supported\")\n\n    from scipy import ndimage\n\n    structure = ndimage.generate_binary_structure(2, 1 if connectivity == 4 else 2)\n    labels, count = ndimage.label(_validate_binary_image(image), structure=structure)\n    return int(count), np.ascontiguousarray(labels, dtype=np.int32)\n\n\ndef _connected_components(\n    image: npt.NDArray[Any],\n    labels: npt.NDArray[Any] | None = None,\n    connectivity: int = 8,\n    ltype: int = 4,\n) -> tuple[int, npt.NDArray[np.int32]]:\n    \"\"\"Return OpenCV-shaped connected-component labels and their count.\"\"\"\n    del ltype\n    count, result = _label(image, connectivity)\n    if labels is not None and labels.shape == result.shape and labels.dtype == np.int32:","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/_cv2/_components.py#L6-L42","documentation":"OpenCV's connectedComponents supports only 4-connectivity (edge adjacency) and 8-connectivity (edge + corner adjacency). The fallback maps these to scipy binary structures of rank 1 and 2; any other value (0, 2, 16, etc.) has no defined structure and raises ValueError.","triggerScenarios":"Calling cv2.connectedComponents(mask, connectivity=x) with x not in {4, 8} — e.g. 0 from an unset variable, or mistaken values like 2.","commonSituations":"Config parameters defaulting to 0/None and passed through unvalidated; developers guessing connectivity values; constants copied from a different library's API.","solutions":["Pass connectivity=4 or connectivity=8 explicitly.","Validate config-supplied connectivity against (4, 8) at load time with a clear error.","Default to 8 when the parameter is optional in your own API."],"exampleFix":"# before\ncount, labels = cv2.connectedComponents(mask, connectivity=cfg.connectivity)  # may be 0\n\n# after\nif cfg.connectivity not in (4, 8):\n    raise ValueError(f'connectivity must be 4 or 8, got {cfg.connectivity}')\ncount, labels = cv2.connectedComponents(mask, connectivity=cfg.connectivity)","handlingStrategy":"validation","validationCode":"if connectivity not in (4, 8):\n    connectivity = 8\ncount, labels = cv2.connectedComponents(mask, connectivity=connectivity)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only pass 4 or 8","Default unset config values to 8","Reject other values at the config boundary with a clear message"],"tags":["opencv-fallback","connected-components","connectivity","input-validation"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}