roboflow/supervision · error · ValueError
Detections class_id must be an integer for Pascal VOC export
Error message
Detections class_id must be an integer for Pascal VOC export, got {type(class_id)}. What it means
Raised by detections_to_pascal_voc when a detection's class_id is neither a Python int nor a NumPy integer. When iterating a Detections, unpacked per-detection values are normally np.int64, so this fires when class_id was stored as a float or other type — VOC writes <name> via classes[class_id], which requires integer indexing.
Source
Thrown at src/supervision/dataset/formats/pascal_voc.py:163
# 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
)
annotation.append(next_object)
else:View on GitHub (pinned to 7f254d9784)
Solutions
- Cast to integer dtype when building Detections: class_id=np.asarray(raw_ids, dtype=int).
- After .tolist() on a float tensor, re-wrap with np.array(..., dtype=int).
- Verify detections.class_id.dtype.kind == 'i' before export.
Example fix
// before detections = sv.Detections(xyxy=boxes, class_id=np.array([0.0, 1.0])) // after detections = sv.Detections(xyxy=boxes, class_id=np.array([0.0, 1.0], dtype=int))
Defensive patterns
Strategy: type-guard
Validate before calling
raw_ids = [0.0, 1.0] # e.g. from JSON
detections = sv.Detections(
xyxy=boxes,
class_id=np.asarray(raw_ids, dtype=int), # coerce floats to int up front
) Type guard
def class_id_is_integer(dets: sv.Detections) -> bool:
"""True when class_id exists and has an integer dtype."""
return dets.class_id is not None and dets.class_id.dtype.kind in ("i", "u") Try / catch
try:
save_pascal_voc_annotations(dataset=ds, annotations_directory_path=out_dir)
except ValueError as exc:
if "must be an integer" in str(exc):
raise TypeError("Coerce class_id to int dtype before VOC export") from exc
raise Prevention
- Always build class_id with an explicit integer dtype: np.array(ids, dtype=int).
- After tensor.tolist() on float tensors, re-wrap with dtype=int.
- Watch for dtype upcast to float when concatenating class_id with float arrays.
When it happens
Trigger: class_id=np.array([0.0, 1.0]) (float dtype), class_id from a JSON-parsed list of floats, or a tensor converted with .tolist() on a float tensor, passed to save_pascal_voc_annotations / detections_to_pascal_voc.
Common situations: Loading class ids from JSON/YAML where they became floats; converting model logits/argmax outputs with dtype float32; concatenating arrays that upcast int to float.
Related errors
- Detections must include class_id for Pascal VOC export.
- Detection annotation for image {image_path} contains non-int
- Detections must include class_id for COCO export.
- class_id is required for CreateML export, but the provided D
- edges is a dict but class_id is None; KeyPoints must have cl
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/892ec06dc6596f13.
Report an issue: GitHub.