{"record":{"id":"87d1ce725b958f1e","repo":"roboflow/supervision","slug":"detections-must-have-class-id-attribute","errorCode":null,"errorMessage":"Detections must have class_id attribute.","messagePattern":"Detections must have class_id attribute\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/dataset/utils.py","lineNumber":127,"sourceCode":"    index_mapping = {}\n\n    for i, class_name in enumerate(source_classes):\n        if class_name not in target_classes:\n            raise ValueError(\n                f\"Class {class_name} not found in target classes. \"\n                \"source_classes must be a subset of target_classes.\"\n            )\n        corresponding_index = target_classes.index(class_name)\n        index_mapping[i] = corresponding_index\n\n    return index_mapping\n\n\ndef map_detections_class_id(\n    source_to_target_mapping: dict[int, int], detections: Detections\n) -> Detections:\n    if detections.class_id is None:\n        raise ValueError(\"Detections must have class_id attribute.\")\n    if set(np.unique(detections.class_id)) - set(source_to_target_mapping.keys()):\n        raise ValueError(\n            \"Detections class_id must be a subset of source_to_target_mapping keys.\"\n        )\n\n    detections_copy = copy.deepcopy(detections)\n\n    if len(detections) > 0:\n        detections_copy.class_id = np.vectorize(source_to_target_mapping.get)(\n            detections_copy.class_id\n        )\n\n    return detections_copy\n\n\ndef check_no_basename_collisions(\n    image_paths: list[str],\n    key: Callable[[str], str],","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/dataset/utils.py#L109-L145","documentation":"Raised by map_detections_class_id() when detections.class_id is None. The function's whole job is to remap class ids from a source dataset's indexing to a target dataset's indexing via np.vectorize over the class_id array; without class_id there is nothing to map and silently returning unchanged detections would hide the mistake.","triggerScenarios":"Calling map_detections_class_id(mapping, detections) on Detections built without class_id — e.g. sv.Detections(xyxy=boxes, confidence=scores) with no class_id, or output of a connector that does not emit class ids.","commonSituations":"Exporting/merging datasets where some annotations lack class labels; running detection with a class-agnostic model; forgetting class_id in a manually-constructed Detections during dataset conversion.","solutions":["Ensure the upstream model/connector populates class_id (pass class ids when constructing Detections).","If the detections are genuinely single-class, assign a placeholder class_id (e.g. np.zeros(len(detections), dtype=np.int64)) before mapping.","Skip the remap for detections without class_id if your pipeline permits."],"exampleFix":"// before\ndets = sv.Detections(xyxy=boxes, confidence=scores)\nmapped = map_detections_class_id(mapping, dets)  # ValueError\n\n// after\ndets = sv.Detections(xyxy=boxes, confidence=scores, class_id=np.zeros(len(boxes), dtype=np.int64))\nmapped = map_detections_class_id(mapping, dets)","handlingStrategy":"validation","validationCode":"if detections.class_id is None:\n    detections = replace(\n        detections,\n        class_id=np.zeros(len(detections), dtype=np.int64),\n    )\nmapped = map_detections_class_id(mapping, detections)","typeGuard":"def has_class_id(dets: sv.Detections) -> bool:\n    return dets.class_id is not None","tryCatchPattern":null,"preventionTips":["Ensure model connectors emit class_id before dataset export workflows.","Assign a default class_id (zeros) for class-agnostic pipelines that later remap classes.","Check detections.class_id is not None before any class-mapping call."],"tags":["dataset","class-id","detections","validation"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}