roboflow/supervision · error · ValueError

Detections class_id must be a subset of source_to_target_map

Error message

Detections class_id must be a subset of source_to_target_mapping keys.

What it means

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.

Source

Thrown at src/supervision/dataset/utils.py:129

    for i, class_name in enumerate(source_classes):
        if class_name not in target_classes:
            raise ValueError(
                f"Class {class_name} not found in target classes. "
                "source_classes must be a subset of target_classes."
            )
        corresponding_index = target_classes.index(class_name)
        index_mapping[i] = corresponding_index

    return index_mapping


def map_detections_class_id(
    source_to_target_mapping: dict[int, int], detections: Detections
) -> Detections:
    if detections.class_id is None:
        raise ValueError("Detections must have class_id attribute.")
    if set(np.unique(detections.class_id)) - set(source_to_target_mapping.keys()):
        raise ValueError(
            "Detections class_id must be a subset of source_to_target_mapping keys."
        )

    detections_copy = copy.deepcopy(detections)

    if len(detections) > 0:
        detections_copy.class_id = np.vectorize(source_to_target_mapping.get)(
            detections_copy.class_id
        )

    return detections_copy


def check_no_basename_collisions(
    image_paths: list[str],
    key: Callable[[str], str],
    output_kind: str,
) -> None:

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Filter detections to known classes first: detections = detections[np.isin(detections.class_id, list(mapping.keys()))].
  2. 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).
  3. If extra classes should map to one bucket, add explicit entries for them.

Example fix

// before
mapped = map_detections_class_id(mapping, dets)  # dets contain unmapped ids

// after
known = np.isin(dets.class_id, list(mapping.keys()))
mapped = map_detections_class_id(mapping, dets[known])
Defensive patterns

Strategy: validation

Validate before calling

valid_ids = set(source_to_target_mapping)
if not set(np.unique(detections.class_id)) <= valid_ids:
    detections = detections[np.isin(detections.class_id, list(valid_ids))]
mapped = map_detections_class_id(source_to_target_mapping, detections)

Type guard

def fully_mapped(mapping: dict[int, int], dets: sv.Detections) -> bool:
    return set(np.unique(dets.class_id)) <= set(mapping)

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15). Data as JSON: /api/errors/da5fc728eb779405. Report an issue: GitHub.