roboflow/supervision · error · ValueError
KeyPoints class_id must be given for NMS to be executed. If
Error message
KeyPoints class_id must be given for NMS to be executed. If you intended to perform class agnostic NMS set class_agnostic=True.
What it means
Raised by KeyPoints.with_nms() when class_id is None and class_agnostic is False. Standard NMS suppresses overlaps only within the same class, which requires class_id; supervision makes this requirement explicit and tells you the escape hatch: set class_agnostic=True to suppress across all classes without class_id.
Source
Thrown at src/supervision/key_points/core.py:1355
from rfdetr import RFDETRKeypointPreview
image = cv2.imread("<SOURCE_IMAGE_PATH>")
model = RFDETRKeypointPreview()
key_points = model.predict(image)
key_points = key_points.with_nms(threshold=0.5)
```
"""
if len(self) == 0:
return self
if self.detection_confidence is None:
raise ValueError(
"KeyPoints detection_confidence must be given for NMS to be executed."
)
if not class_agnostic and self.class_id is None:
raise ValueError(
"KeyPoints class_id must be given for NMS to be executed. If "
"you intended to perform class agnostic NMS set "
"class_agnostic=True."
)
xy = self.xy
valid = ~np.all(xy == 0, axis=-1)
if self.visible is not None:
valid = valid & self.visible
x_min = np.min(np.where(valid, xy[..., 0], np.inf), axis=1)
y_min = np.min(np.where(valid, xy[..., 1], np.inf), axis=1)
x_max = np.max(np.where(valid, xy[..., 0], -np.inf), axis=1)
y_max = np.max(np.where(valid, xy[..., 1], -np.inf), axis=1)
xyxy = np.stack([x_min, y_min, x_max, y_max], axis=1).astype(np.float32)
if class_agnostic:
predictions = np.hstack([xyxy, self.detection_confidence.reshape(-1, 1)])
else:View on GitHub (pinned to 7f254d9784)
Solutions
- If detections are all one class or class boundaries do not matter: key_points.with_nms(threshold=0.5, class_agnostic=True).
- Otherwise pass class_id when constructing KeyPoints so class-aware NMS can group by class.
Example fix
// before kp = kp.with_nms(threshold=0.5) # no class_id -> ValueError // after kp = kp.with_nms(threshold=0.5, class_agnostic=True)
Defensive patterns
Strategy: validation
Validate before calling
if kp.class_id is None:
kp = kp.with_nms(threshold=0.5, class_agnostic=True)
else:
kp = kp.with_nms(threshold=0.5) Type guard
def nms_kwargs(kp: sv.KeyPoints) -> dict:
return {"class_agnostic": kp.class_id is None} Prevention
- Populate class_id on multi-class KeyPoints so class-aware NMS works.
- Default to class_agnostic=True when your pipeline is single-class.
- Remember with_nms defaults to class-aware NMS, unlike some other libraries.
When it happens
Trigger: Calling key_points.with_nms(threshold=0.5) (class_agnostic defaults to False) on KeyPoints that lack class_id — e.g. a single-person pose result or a connector that does not emit class ids.
Common situations: Running NMS on pose/keypoint output from a single-class model that never populated class_id; forgetting that with_nms defaults to class-aware NMS unlike the intended use case.
Related errors
- KeyPoints detection_confidence must be given for NMS to be e
- All KeyPoints must have the same coordinate depth per skelet
- Cannot pass both 'confidence' and 'keypoint_confidence'. 'co
- All or none of the '{name}' fields must be None
- Detections must have class_id attribute.
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/922722c9bcb88038.
Report an issue: GitHub.