roboflow/supervision · error · ValueError

At least one channel is required

Error message

At least one channel is required

What it means

The fallback `cv2.merge` at src/supervision/_cv2/_color.py:93 stacks a sequence of single-channel arrays along the last axis; merging an empty sequence has no defined shape/dtype, so it raises ValueError. Mirrors OpenCV's own requirement of at least one channel.

Source

Thrown at src/supervision/_cv2/_color.py:93

    green = np.choose(sector_index, (x, chroma, chroma, x, zeros, zeros))
    blue = np.choose(sector_index, (zeros, zeros, x, chroma, chroma, x))
    bgr = np.stack((blue + match, green + match, red + match), axis=-1) * 255
    return _cast_array_like_opencv(bgr, image.dtype)


def _split(image: npt.NDArray[Any]) -> tuple[npt.NDArray[Any], ...]:
    """Split an image into contiguous single-channel arrays."""
    if image.ndim == 2:
        return (np.ascontiguousarray(image),)
    return tuple(
        np.ascontiguousarray(image[..., index]) for index in range(image.shape[2])
    )


def _merge(channels: Sequence[npt.NDArray[Any]]) -> npt.NDArray[Any]:
    """Merge single-channel arrays along their final axis."""
    if not channels:
        raise ValueError("At least one channel is required")
    return np.ascontiguousarray(np.stack(channels, axis=-1))

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Guard before merging: `if not channels: skip or raise a domain error`
  2. Fix the upstream filter so it always yields >= 1 channel
  3. Default to a concrete channel list when the dynamic selection is empty

Example fix

// before
merged = cv2.merge(selected_channels)  # selected_channels may be []

// after
if not selected_channels:
    raise ValueError(f'no channels selected from {source}')
merged = cv2.merge(selected_channels)
Defensive patterns

Strategy: validation

Validate before calling

def merge_channels(channels):
    """Merge only a non-empty channel sequence."""
    if not channels:
        raise ValueError("cannot merge zero channels")
    return cv2.merge(channels)

Type guard

def is_mergeable(channels) -> bool:
    """cv2.merge requires at least one channel array."""
    return len(channels) > 0

Prevention

When it happens

Trigger: Calling `cv2.merge([])` or `cv2.merge(channels)` where `channels` is an empty list/tuple — commonly when channels are produced by filtering/slicing that can return zero elements (e.g. `cv2.split(img)[::3]` style code, or a loop building channels from a zero-length iterable).

Common situations: Dynamic channel selection where the selection set is empty for some inputs; iterating over contours/masks that yield no channel arrays and forwarding the result unconditionally.

Related errors


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