roboflow/supervision · error · ValueError

Class {class_name} not found in target classes. source_class

Error message

Class {class_name} not found in target classes. source_classes must be a subset of target_classes.

What it means

Raised by build_class_index_mapping() when a class name in source_classes does not appear in target_classes. The function produces a source-index → target-index dict used to re-index annotations between datasets; a source class absent from the target list has no valid target index, so it fails with a subset requirement message.

Source

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

def merge_class_lists(class_lists: list[list[str]]) -> list[str]:
    unique_classes = set()

    for class_list in class_lists:
        for class_name in class_list:
            unique_classes.add(class_name)

    return sorted(list(unique_classes))


def build_class_index_mapping(
    source_classes: list[str], target_classes: list[str]
) -> dict[int, int]:
    """Returns the index map of source classes -> target classes."""
    index_mapping = {}

    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."
        )

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Build the target class list with supervision.merge_class_lists() (used internally by merge) so it is the union of all datasets' classes.
  2. Normalize class name strings (strip/casefold) before comparing if names differ only by case or whitespace.
  3. Drop or rename the extra source classes that the target genuinely should not contain.

Example fix

// before
mapping = build_class_index_mapping(src_ds.classes, tgt_ds.classes)  # tgt missing classes

// after
from supervision.dataset.utils import merge_class_lists
merged_classes = merge_class_lists([src_ds.classes, tgt_ds.classes])
mapping = build_class_index_mapping(src_ds.classes, merged_classes)
Defensive patterns

Strategy: validation

Validate before calling

missing = [c for c in source_classes if c not in target_classes]
if missing:
    target_classes = merge_class_lists([target_classes, source_classes])
mapping = build_class_index_mapping(source_classes, target_classes)

Type guard

def is_subset(source: list[str], target: list[str]) -> bool:
    return set(source) <= set(target)

Prevention

When it happens

Trigger: Calling build_class_index_mapping(source_classes=['cat','dog','person'], target_classes=['cat','dog']) — 'person' is not in target. Common when merging two detection datasets whose class lists were collected independently.

Common situations: Using DetectionDataset.merge() or as_yolo/as_voc exports where classes differ across datasets; target classes derived from one dataset's annotations while the source has extra labels; case/whitespace differences in class names ('Cat' vs 'cat').

Related errors


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