{"record":{"id":"da5fc728eb779405","repo":"roboflow/supervision","slug":"detections-class-id-must-be-a-subset-of-source-to","errorCode":null,"errorMessage":"Detections class_id must be a subset of source_to_target_mapping keys.","messagePattern":"Detections class_id must be a subset of source_to_target_mapping keys\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/dataset/utils.py","lineNumber":129,"sourceCode":"    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],\n    output_kind: str,\n) -> None:","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/dataset/utils.py#L111-L147","documentation":"Raised by map_detections_class_id() when detections contain class ids that have no entry in the source_to_target_mapping dict. The remap uses mapping.get(); unmapped ids would become None and corrupt the array, so supervision validates that detections.class_id ⊆ mapping.keys() first.","triggerScenarios":"Calling map_detections_class_id(mapping, detections) where the mapping was built from class lists that do not cover every class present in detections — e.g. detections from a model with 80 COCO classes mapped with a mapping built from a 10-class target subset.","commonSituations":"Merging datasets or exporting to YOLO/VOC where the target class list is a subset of the source; class lists built from annotation files that missed a rarely-occurring class; filter detections before remapping.","solutions":["Filter detections to known classes first: detections = detections[np.isin(detections.class_id, list(mapping.keys()))].","Extend the mapping so it covers every class id present in the detections (rebuild with build_class_index_mapping over the full source class list).","If extra classes should map to one bucket, add explicit entries for them."],"exampleFix":"// before\nmapped = map_detections_class_id(mapping, dets)  # dets contain unmapped ids\n\n// after\nknown = np.isin(dets.class_id, list(mapping.keys()))\nmapped = map_detections_class_id(mapping, dets[known])","handlingStrategy":"validation","validationCode":"valid_ids = set(source_to_target_mapping)\nif not set(np.unique(detections.class_id)) <= valid_ids:\n    detections = detections[np.isin(detections.class_id, list(valid_ids))]\nmapped = map_detections_class_id(source_to_target_mapping, detections)","typeGuard":"def fully_mapped(mapping: dict[int, int], dets: sv.Detections) -> bool:\n    return set(np.unique(dets.class_id)) <= set(mapping)","tryCatchPattern":null,"preventionTips":["Build the mapping from the full source class list, not a subset.","Filter detections to mapped classes before remapping.","Unit-test that model output class ids are covered by the mapping."],"tags":["dataset","class-id","mapping","validation"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}