roboflow/supervision · error · ValueError

All sigma values must be positive

Error message

All sigma values must be positive

What it means

Raised by sv.Color.from_bgr_tuple when any element of the (b, g, r) tuple is outside 0-255. Note the message prints the values in BGR order because that is the order you supplied. OpenCV natively uses BGR, so this method is the entry point for colors coming straight from cv2 code; the range check happens before the values are swapped into the Color dataclass's RGB fields.

Source

Thrown at src/supervision/key_points/annotators.py:295

    Handles sigma/color validation, sorting, covariance extraction and
    eigendecomposition shared by all VertexEllipse* variants.
    """

    def __init__(
        self,
        sigma: float | Sequence[float] = (1.0, 2.0, 3.0),
        color: Color | Sequence[Color] = (Color.GREEN, Color.YELLOW, Color.RED),
        max_axis: float | None = None,
    ) -> None:
        sigma_seq: Sequence[float] = (
            (sigma,) if isinstance(sigma, (int, float)) else sigma
        )
        color_seq: Sequence[Color] = (color,) if isinstance(color, Color) else color

        if len(sigma_seq) == 0:
            raise ValueError("sigma must contain at least one value")
        if any(s <= 0 for s in sigma_seq):
            raise ValueError("All sigma values must be positive")
        if max_axis is not None and max_axis <= 0:
            raise ValueError("max_axis must be positive when provided")
        if len(color_seq) != len(sigma_seq):
            raise ValueError(
                f"color length ({len(color_seq)}) must match "
                f"sigma length ({len(sigma_seq)})"
            )

        sorted_indices = sorted(
            range(len(sigma_seq)), key=lambda i: sigma_seq[i], reverse=True
        )
        self.sigma = [sigma_seq[i] for i in sorted_indices]
        self.color = [color_seq[i] for i in sorted_indices]
        self.max_axis = max_axis

    def _get_covariances(self, key_points: KeyPoints) -> npt.NDArray[np.float32]:
        covariances = key_points.data.get("covariance")
        if covariances is None:

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Clamp each BGR element to 0-255 with max(0, min(255, v)) before calling.
  2. When extracting colors from images with NumPy/OpenCV, cast to int() explicitly since uint8 overflow wraps around (250 + 10 becomes 4, not 260).
  3. Confirm you are actually passing BGR order, not RGB; the values in the error message appear in BGR order as given.
  4. For colors from cv2.mean or similar, round and clamp before conversion.

Example fix

# before
avg = cv2.mean(roi)[:3]  # floats, may exceed expectations
color = sv.Color.from_bgr_tuple(avg)

# after
bgr = tuple(max(0, min(255, int(round(v)))) for v in cv2.mean(roi)[:3])
color = sv.Color.from_bgr_tuple(bgr)
Defensive patterns

Strategy: validation

Validate before calling

def safe_bgr(bgr: tuple) -> tuple[int, int, int]:
    """Clamp/cast a BGR triple (e.g. from cv2.mean) for from_bgr_tuple."""
    return tuple(max(0, min(255, int(round(v)))) for v in bgr)  # type: ignore[return-value]

Type guard

def is_valid_bgr_tuple(t: tuple) -> bool:
    """True if t is three numbers each within 0-255 (BGR order)."""
    return len(t) == 3 and all(isinstance(v, (int, float)) and 0 <= v <= 255 for v in t)

Prevention

When it happens

Trigger: sv.Color.from_bgr_tuple((256, 0, 0)), negative values from image-processing arithmetic, or handing a NumPy uint8-overflowed value (e.g. np.uint8 arithmetic wrapping) into the method without casting back to a bounded int.

Common situations: Bridging cv2 pipelines (masks, mean-color extraction via cv2.mean) into supervision annotators; sampling pixel values from images and using them as annotation colors; converting between libraries where channel order and dtype conventions differ, causing off-by-range values.

Related errors


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