roboflow/supervision · error · ValueError
Detections must include class_id for Pascal VOC export.
Error message
Detections must include class_id for Pascal VOC export.
What it means
Raised by detections_to_pascal_voc while iterating Detections when a detection's class_id is None. VOC XML requires a <name> element derived from classes[class_id] for every object, so class-less detections cannot be serialized.
Source
Thrown at src/supervision/dataset/formats/pascal_voc.py:161
database.text = "roboflow.ai"
# Add size element
size = SubElement(annotation, "size")
w = SubElement(size, "width")
w.text = str(width)
h = SubElement(size, "height")
h.text = str(height)
d = SubElement(size, "depth")
d.text = str(depth)
# Add segmented element
segmented = SubElement(annotation, "segmented")
segmented.text = "0"
# Add object elements
for xyxy, mask, _, class_id, _, _ in detections:
if class_id is None:
raise ValueError("Detections must include class_id for Pascal VOC export.")
if not isinstance(class_id, (int, np.integer)):
raise ValueError(
f"Detections class_id must be an integer for Pascal VOC export, "
f"got {type(class_id)!r}."
)
name = classes[class_id]
if mask is not None:
polygons = approximate_mask_with_polygons(
mask=mask,
min_image_area_percentage=min_image_area_percentage,
max_image_area_percentage=max_image_area_percentage,
approximation_percentage=approximation_percentage,
)
for polygon in polygons:
xyxy = polygon_to_xyxy(polygon=polygon)
next_object = object_to_pascal_voc(
xyxy=xyxy, name=name, polygon=polygon
)View on GitHub (pinned to 7f254d9784)
Solutions
- Construct Detections with class_id: sv.Detections(xyxy=boxes, class_id=ids).
- For single-class exports, use class_id=np.zeros(len(boxes), dtype=int) and classes=["object"].
- Assert detections.class_id is not None before export.
Example fix
// before detections = sv.Detections(xyxy=boxes) // after detections = sv.Detections(xyxy=boxes, class_id=np.zeros(len(boxes), dtype=int))
Defensive patterns
Strategy: type-guard
Validate before calling
if detections.class_id is None:
detections = sv.Detections(
xyxy=detections.xyxy,
confidence=detections.confidence,
class_id=np.zeros(len(detections), dtype=int),
) Type guard
def has_class_id(dets: sv.Detections) -> bool:
"""True when class_id is present for every detection."""
return dets.class_id is not None and len(dets.class_id) == len(dets) Try / catch
try:
save_pascal_voc_annotations(dataset=ds, annotations_directory_path=out_dir)
except ValueError as exc:
if "class_id" in str(exc):
raise RuntimeError("Cannot write VOC XML without class ids") from exc
raise Prevention
- Attach class_id at Detections construction time, always.
- Route class-agnostic outputs through a fixed single-class mapping before export.
- Assert class_id presence in dataset-conversion scripts before the write loop.
When it happens
Trigger: Calling save_pascal_voc_annotations on a DetectionDataset whose Detections were built without class_id, or calling detections_to_pascal_voc directly with sv.Detections(xyxy=..., confidence=...).
Common situations: Class-agnostic detector outputs; custom box lists assembled for dataset conversion; Detections filtered or transformed in a way that drops class_id.
Related errors
- Detections must include class_id for COCO export.
- class_id is required for CreateML export, but the provided D
- Detections class_id must be an integer for Pascal VOC export
- Detections must have class_id attribute.
- Class ID is required for YOLO annotations.
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/202a01a1ed63cb95.
Report an issue: GitHub.