roboflow/supervision · error · ValueError

Only RETR_TREE is supported by the fallback

Error message

Only RETR_TREE is supported by the fallback

What it means

The fallback `findContours` in src/supervision/_cv2/_contours.py:145 implements only the retrieval mode supervision itself uses (`RETR_TREE`); it maps every other mode constant onto that check and raises for anything else. Without OpenCV, modes like RETR_EXTERNAL, RETR_LIST, or RETR_CCOMP are not emulated because they imply different contour sets/relationships.

Source

Thrown at src/supervision/_cv2/_contours.py:145

    for index, point in enumerate(contour):
        previous = point - contour[index - 1]
        following = contour[(index + 1) % len(contour)] - point
        if (
            np.any(previous)
            and np.any(following)
            and np.array_equal(np.sign(previous), np.sign(following))
        ):
            continue
        keep.append(point)
    return np.asarray(keep, dtype=np.int32)


def _find_contours(
    image: npt.NDArray[Any], mode: int, method: int
) -> tuple[list[npt.NDArray[np.int32]], npt.NDArray[np.int32] | None]:
    """Find contours for the supported tree and SIMPLE modes."""
    if mode != _RETR_TREE:
        raise ValueError("Only RETR_TREE is supported by the fallback")
    if method != _CHAIN_APPROX_SIMPLE:
        raise ValueError("Only CHAIN_APPROX_SIMPLE is supported by the fallback")
    values = np.asarray(image)
    if values.ndim != 2:
        raise ValueError("Contour input must be a two-dimensional image")
    traced = [_compress_contour(contour) for contour in _trace_borders(values != 0)]
    if not traced:
        return [], None
    return [contour.reshape(-1, 1, 2) for contour in traced], None

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Use `mode=cv2.RETR_TREE` and filter contours yourself (e.g. drop contours that are holes by checking parents in hierarchy or by area)
  2. Install `opencv-python` if the retrieval mode semantics matter for your pipeline
  3. Pre-filter the mask (e.g. fill holes) so RETR_TREE results match what RETR_EXTERNAL would have returned

Example fix

// before
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

// after
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
outer = [c for c in contours if cv2.contourArea(c) >= min_area]  # approximate filtering
Defensive patterns

Strategy: fallback

Validate before calling

from supervision._cv2 import BACKEND_NAME  # 'opencv' or 'fallback'

SUPPORTED_RETRIEVAL = {"RETR_TREE"}

def assert_retrieval_supported(mode_name: str) -> None:
    """Fail fast when a contour retrieval mode is unavailable on the fallback."""
    if BACKEND_NAME != "opencv" and mode_name not in SUPPORTED_RETRIEVAL:
        raise ValueError(f"contour mode {mode_name} needs opencv-python installed")

Prevention

When it happens

Trigger: Calling `cv2.findContours` with `mode=cv2.RETR_EXTERNAL` (the most common alternative) while running on the fallback backend; also any typo'd or custom mode integer.

Common situations: Code written against real OpenCV using RETR_EXTERNAL to get only outer contours, then run in a slim container without opencv-python; mixing cv2 constant values copied from a different OpenCV version.

Related errors


AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15). Data as JSON: /api/errors/b2e2054dd3c79a3d. Report an issue: GitHub.