roboflow/supervision · error · ValueError

Detections class_id must be given for {operation_name} to be

Error message

Detections class_id must be given for {operation_name} to be executed. If you intended to perform class agnostic {operation_name} set class_agnostic=True.

What it means

The internal _build_nms_predictions helper stacks xyxy, confidence, and (unless class_agnostic) class_id for the NMS/NMM/Soft-NMS dispatchers. Class-aware suppression needs class_id to compare boxes within the same class; if class_id is None and class_agnostic=False, it raises this error naming the operation that failed.

Source

Thrown at src/supervision/detection/core.py:2989

        )
        return new

    def _build_nms_predictions(
        self, class_agnostic: bool, operation_name: str
    ) -> npt.NDArray[np.floating]:
        """Stack xyxy + confidence (+ class_id) for NMS/NMM/Soft-NMS dispatch.

        Callers must already have verified `self.confidence is not None`.
        """
        if class_agnostic:
            return cast(
                npt.NDArray[np.floating],
                np.hstack(
                    (self.xyxy, cast(np.ndarray, self.confidence).reshape(-1, 1))
                ),
            )
        if self.class_id is None:
            raise ValueError(
                f"Detections class_id must be given for {operation_name} to be "
                f"executed. If you intended to perform class agnostic "
                f"{operation_name} set class_agnostic=True."
            )
        return cast(
            npt.NDArray[np.floating],
            np.hstack(
                (
                    self.xyxy,
                    cast(np.ndarray, self.confidence).reshape(-1, 1),
                    self.class_id.reshape(-1, 1),
                )
            ),
        )

    def with_nms(
        self,
        threshold: float = 0.5,

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Pass class_agnostic=True if cross-class suppression is acceptable: detections.with_nms(threshold=0.5, class_agnostic=True).
  2. Populate class_id before suppression if you have class info (even a zeros array for a single class): cls(xyxy=..., confidence=..., class_id=np.zeros(len(xyxy), dtype=int)).
  3. For OCR text duplicates, consider deduplicating on data[CLASS_NAME_DATA_FIELD] yourself instead of class-aware NMS.

Example fix

# before
detections = sv.Detections(xyxy=boxes, confidence=scores)
clean = detections.with_nms(threshold=0.5)  # ValueError: class_id missing

# after
detections = sv.Detections(
    xyxy=boxes,
    confidence=scores,
    class_id=np.zeros(len(boxes), dtype=int),
)
clean = detections.with_nms(threshold=0.5)
# or: clean = detections.with_nms(threshold=0.5, class_agnostic=True)
Defensive patterns

Strategy: validation

Validate before calling

def can_run_class_aware_nms(dets: sv.Detections) -> bool:
    return dets.class_id is not None

clean = (
    detections.with_nms(threshold=0.5)
    if can_run_class_aware_nms(detections)
    else detections.with_nms(threshold=0.5, class_agnostic=True)
)

Type guard

def has_class_id(dets: sv.Detections) -> bool:
    return dets.class_id is not None

Try / catch

try:
    clean = detections.with_nms(threshold=0.5)
except ValueError as e:
    if 'class_agnostic' in str(e):
        clean = detections.with_nms(threshold=0.5, class_agnostic=True)
    else:
        raise

Prevention

When it happens

Trigger: Calling detections.with_nms(threshold=...), with_soft_nms(...), or with_nmm(...) on a Detections whose class_id is None while class_agnostic is False (the default). This happens with outputs from connectors that don't populate class_id (e.g. some VLM/OCR connectors like from_paddledetection_ocr or from_easyocr, or hand-built cls(xyxy=..., confidence=...)).

Common situations: Building Detections manually from raw boxes+scores and forgetting class_id; applying with_nms to OCR/VLM results that carry only class_name in data; processing model variants that return no class predictions.

Related errors


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