{"record":{"id":"202a01a1ed63cb95","repo":"roboflow/supervision","slug":"detections-must-include-class-id-for-pascal-voc-ex","errorCode":null,"errorMessage":"Detections must include class_id for Pascal VOC export.","messagePattern":"Detections must include class_id for Pascal VOC export\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/dataset/formats/pascal_voc.py","lineNumber":161,"sourceCode":"    database.text = \"roboflow.ai\"\n\n    # Add size element\n    size = SubElement(annotation, \"size\")\n    w = SubElement(size, \"width\")\n    w.text = str(width)\n    h = SubElement(size, \"height\")\n    h.text = str(height)\n    d = SubElement(size, \"depth\")\n    d.text = str(depth)\n\n    # Add segmented element\n    segmented = SubElement(annotation, \"segmented\")\n    segmented.text = \"0\"\n\n    # Add object elements\n    for xyxy, mask, _, class_id, _, _ in detections:\n        if class_id is None:\n            raise ValueError(\"Detections must include class_id for Pascal VOC export.\")\n        if not isinstance(class_id, (int, np.integer)):\n            raise ValueError(\n                f\"Detections class_id must be an integer for Pascal VOC export, \"\n                f\"got {type(class_id)!r}.\"\n            )\n        name = classes[class_id]\n        if mask is not None:\n            polygons = approximate_mask_with_polygons(\n                mask=mask,\n                min_image_area_percentage=min_image_area_percentage,\n                max_image_area_percentage=max_image_area_percentage,\n                approximation_percentage=approximation_percentage,\n            )\n            for polygon in polygons:\n                xyxy = polygon_to_xyxy(polygon=polygon)\n                next_object = object_to_pascal_voc(\n                    xyxy=xyxy, name=name, polygon=polygon\n                )","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/dataset/formats/pascal_voc.py#L143-L179","documentation":"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.","triggerScenarios":"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=...).","commonSituations":"Class-agnostic detector outputs; custom box lists assembled for dataset conversion; Detections filtered or transformed in a way that drops class_id.","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."],"exampleFix":"// before\ndetections = sv.Detections(xyxy=boxes)\n\n// after\ndetections = sv.Detections(xyxy=boxes, class_id=np.zeros(len(boxes), dtype=int))","handlingStrategy":"type-guard","validationCode":"if detections.class_id is None:\n    detections = sv.Detections(\n        xyxy=detections.xyxy,\n        confidence=detections.confidence,\n        class_id=np.zeros(len(detections), dtype=int),\n    )","typeGuard":"def has_class_id(dets: sv.Detections) -> bool:\n    \"\"\"True when class_id is present for every detection.\"\"\"\n    return dets.class_id is not None and len(dets.class_id) == len(dets)","tryCatchPattern":"try:\n    save_pascal_voc_annotations(dataset=ds, annotations_directory_path=out_dir)\nexcept ValueError as exc:\n    if \"class_id\" in str(exc):\n        raise RuntimeError(\"Cannot write VOC XML without class ids\") from exc\n    raise","preventionTips":["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."],"tags":["pascal-voc","detections","class-id","dataset-export"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}