roboflow/supervision · error · ValueError

Empty group detected when non-max-merging detections: {merge

Error message

Empty group detected when non-max-merging detections: {merge_groups}

What it means

An internal invariant check inside non-max-merging group construction: after grouping prediction indices by class id and overlap, every group must contain at least one index. An empty group is impossible when inputs are well-formed (groups are built from `np.where(category_ids == id)` results, which are never empty), so hitting this error means the grouping logic received malformed state — effectively a defensive assert against corrupted predictions arrays or patched internals.

Source

Thrown at src/supervision/detection/utils/iou_and_nms.py:1480

    When ``predictions`` has no class column, a single pass over all rows is
    performed instead of per-category iteration.
    """
    if predictions.shape[1] == 5:
        global_indices = np.arange(len(predictions), dtype=int)
        return [
            global_indices[group].tolist() for group in group_within(global_indices)
        ]

    category_ids = predictions[:, 5]
    merge_groups: list[list[int]] = []
    for category_id in np.unique(category_ids):
        curr_indices = np.where(category_ids == category_id)[0]
        for local_group in group_within(curr_indices):
            merge_groups.append(curr_indices[local_group].tolist())

    for merge_group in merge_groups:
        if len(merge_group) == 0:
            raise ValueError(
                f"Empty group detected when non-max-merging detections: {merge_groups}"
            )
    return merge_groups


def _group_overlapping_boxes(
    predictions: npt.NDArray[np.floating],
    iou_threshold: float = 0.5,
    overlap_metric: OverlapMetric = OverlapMetric.IOU,
) -> list[list[int]]:
    """
    Apply greedy version of non-maximum merging to avoid detecting too many
    overlapping bounding boxes for a given object.

    Args:
        predictions: An array of shape `(n, 5)` containing
            the bounding boxes coordinates in format `[x1, y1, x2, y2]`
            and the confidence scores.

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Use the public API instead: `detections.with_nms(threshold, overlap_filter=sv.OverlapFilter.NON_MAX_MERGE)`.
  2. If you must call internals, build `predictions` as a float array of shape (N, 6): [x_min, y_min, x_max, y_max, confidence, class_id] with no NaNs.
  3. Check your test doubles: a stubbed grouping callback that returns empty lists will trip this guard by design.

Example fix

# before
groups = _group_overlapping_boxes(np.array([[0, 0, 1, 1, 0.9, np.nan]]))  # NaN class id

# after
dets = detections.with_nms(0.5, overlap_filter=sv.OverlapFilter.NON_MAX_MERGE)
Defensive patterns

Strategy: validation

Validate before calling

assert predictions.ndim == 2 and predictions.shape[1] in (5, 6)
assert not np.isnan(predictions.astype(float)).any()

Type guard

def is_valid_predictions(arr) -> bool:
    arr = np.asarray(arr)
    return arr.ndim == 2 and arr.shape[1] in (5, 6)

Try / catch

try:
    dets = dets.with_nms(0.5, overlap_filter=sv.OverlapFilter.NON_MAX_MERGE)
except ValueError as e:
    if 'Empty group' in str(e):
        raise RuntimeError('corrupted detections; rebuild from model output') from e
    raise

Prevention

When it happens

Trigger: Directly calling the private grouping helper `_group_overlapping_boxes` / non-max-merge internals with a hand-built `predictions` array whose shape or dtype breaks the class-id column (e.g. object dtype, NaN class ids making `np.unique`/`np.where` disagree); monkeypatched `group_within` returning empty lists.

Common situations: Almost never seen via the public API (`sv.Detections.with_nms` / `OverlapFilter.NON_MAX_MERGE`); appears when unit tests stub grouping functions or when a custom predictions array with wrong dtype/class column is passed into internal helpers.

Related errors


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