{"record":{"id":"4c75976ea60752cd","repo":"roboflow/supervision","slug":"only-chain-approx-simple-is-supported-by-the-fallb","errorCode":null,"errorMessage":"Only CHAIN_APPROX_SIMPLE is supported by the fallback","messagePattern":"Only CHAIN_APPROX_SIMPLE is supported by the fallback","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/_cv2/_contours.py","lineNumber":147,"sourceCode":"        following = contour[(index + 1) % len(contour)] - point\n        if (\n            np.any(previous)\n            and np.any(following)\n            and np.array_equal(np.sign(previous), np.sign(following))\n        ):\n            continue\n        keep.append(point)\n    return np.asarray(keep, dtype=np.int32)\n\n\ndef _find_contours(\n    image: npt.NDArray[Any], mode: int, method: int\n) -> tuple[list[npt.NDArray[np.int32]], npt.NDArray[np.int32] | None]:\n    \"\"\"Find contours for the supported tree and SIMPLE modes.\"\"\"\n    if mode != _RETR_TREE:\n        raise ValueError(\"Only RETR_TREE is supported by the fallback\")\n    if method != _CHAIN_APPROX_SIMPLE:\n        raise ValueError(\"Only CHAIN_APPROX_SIMPLE is supported by the fallback\")\n    values = np.asarray(image)\n    if values.ndim != 2:\n        raise ValueError(\"Contour input must be a two-dimensional image\")\n    traced = [_compress_contour(contour) for contour in _trace_borders(values != 0)]\n    if not traced:\n        return [], None\n    return [contour.reshape(-1, 1, 2) for contour in traced], None\n","sourceCodeStart":129,"sourceCodeEnd":155,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/_cv2/_contours.py#L129-L155","documentation":"The fallback `findContours` in src/supervision/_cv2/_contours.py:147 only implements `CHAIN_APPROX_SIMPLE` (which compresses straight runs into endpoints); it rejects `CHAIN_APPROX_NONE` and other approximation methods because the fallback's `_compress_contour` stage always produces SIMPLE-style output and emulating the others would diverge silently.","triggerScenarios":"Calling `cv2.findContours` with `method=cv2.CHAIN_APPROX_NONE` (all boundary points) on the fallback backend; passing any approximation flag other than CHAIN_APPROX_SIMPLE.","commonSituations":"Code that needs every boundary pixel (e.g. precise perimeter sampling) written against real OpenCV, then executed where opencv-python is absent.","solutions":["Use `method=cv2.CHAIN_APPROX_SIMPLE` and accept compressed contours (they define the same polygons)","If you truly need all boundary points, densify SIMPLE contours afterwards (e.g. interpolate along segments) or install `opencv-python`","Check `supervision._cv2.BACKEND_NAME` at startup and route to a real cv2 install when the fallback lacks features you use"],"exampleFix":"// before\ncontours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)\n\n// after\ncontours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)","handlingStrategy":"fallback","validationCode":"from supervision._cv2 import BACKEND_NAME\n\nSUPPORTED_METHOD = {\"CHAIN_APPROX_SIMPLE\"}\n\ndef assert_method_supported(method_name: str) -> None:\n    \"\"\"Fail fast when a chain approximation method is unavailable on the fallback.\"\"\"\n    if BACKEND_NAME != \"opencv\" and method_name not in SUPPORTED_METHOD:\n        raise ValueError(f\"contour method {method_name} needs opencv-python installed\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use CHAIN_APPROX_SIMPLE everywhere; the compressed polygons are equivalent for area/drawing","Densify contours yourself if you need every boundary pixel"],"tags":["cv2-fallback","contours","approximation-method"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}