roboflow/supervision · error · ValueError

The keys of the images and annotations dictionaries must mat

Error message

The keys of the images and annotations dictionaries must match.

What it means

Raised by the DetectionDataset constructor when the set of image keys does not equal the set of annotation keys. Every image must have exactly one Detections annotation and vice versa; a mismatch means the dataset would have images without labels or labels pointing at nonexistent images.

Source

Thrown at src/supervision/dataset/core.py:101

            be removed in ``0.33.0``; use a list of paths instead.
            When a list of paths is provided, images are loaded lazily on
            demand, which is more memory-efficient.
        annotations: Dictionary mapping
            image path to annotations. The dictionary keys match
            match the keys in `images` or entries in the list of
            image paths.
    """

    def __init__(
        self,
        classes: list[str],
        images: list[str] | dict[str, npt.NDArray[np.uint8]],
        annotations: dict[str, Detections],
    ) -> None:
        self.classes = classes

        if set(images) != set(annotations):
            raise ValueError(
                "The keys of the images and annotations dictionaries must match."
            )
        self.annotations = {
            image_path: deepcopy(annotation)
            for image_path, annotation in annotations.items()
        }

        np_classes = np.array(self.classes)
        for image_path, annotation in self.annotations.items():
            class_ids = annotation.class_id
            if class_ids is None:
                continue
            if not np.issubdtype(class_ids.dtype, np.integer):
                raise ValueError(
                    f"Detection annotation for image {image_path!r} contains "
                    f"non-integer class_id values with dtype {class_ids.dtype}."
                )

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Intersect the two key sets before constructing: keep = set(images) & set(annotations), then filter both.
  2. Normalize paths (same suffix, same prefix, os.path.normpath) so keys compare equal.
  3. Log the symmetric difference set(images) ^ set(annotations) to see exactly which keys mismatch.

Example fix

// before
images = {p: cv2.imread(p) for p in glob('images/*')}
ds = DetectionDataset(classes=c, images=images, annotations=anns)  # key mismatch

// after
keep = sorted(set(images) & set(anns))
ds = DetectionDataset(classes=c, images=[p for p in keep], annotations={p: anns[p] for p in keep})
Defensive patterns

Strategy: validation

Validate before calling

if set(images) != set(annotations):
    keep = set(images) & set(annotations)
    missing = set(images) ^ set(annotations)
    print(f"Skipping unmatched entries: {missing}")
    images = {p: images[p] for p in images if p in keep} if isinstance(images, dict) else [p for p in images if p in keep]
    annotations = {p: annotations[p] for p in annotations if p in keep}
ds = DetectionDataset(classes=classes, images=images, annotations=annotations)

Type guard

def keys_match(images, annotations: dict) -> bool:
    return set(images) == set(annotations)

Prevention

When it happens

Trigger: Calling DetectionDataset(classes=..., images={'a.jpg': img}, annotations={'b.jpg': dets}) — key 'a.jpg' vs 'b.jpg'. Also when passing images as a list while the annotations dict keys don't exactly match the list entries (set comparison still applies).

Common situations: Building a dataset from globbed image files and a parsed annotations dict where some images failed to parse or some annotation files have no matching image; off-by-one filename differences ('.jpeg' vs '.jpg'); leading './' in one set but not the other.

Related errors


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