open-mmlab/mmdetection · error · ValueError

dataset metainfo must contain `classes`

Error message

dataset metainfo must contain `classes`

What it means

ClassAwareSampler builds a category-to-image index by reading dataset.metainfo['classes']; if the wrapped dataset has no 'classes' key in its metainfo (e.g. it is a plain base dataset or a wrapper that drops metainfo), sampling cannot proceed and ValueError is raised during __init__.

Source

Thrown at mmdet/datasets/samplers/class_aware_sampler.py:80

        # get number of images containing each category
        self.num_cat_imgs = [len(x) for x in self.cat_dict.values()]
        # filter labels without images
        self.valid_cat_inds = [
            i for i, length in enumerate(self.num_cat_imgs) if length != 0
        ]
        self.num_classes = len(self.valid_cat_inds)

    def get_cat2imgs(self) -> Dict[int, list]:
        """Get a dict with class as key and img_ids as values.

        Returns:
            dict[int, list]: A dict of per-label image list,
            the item of the dict indicates a label index,
            corresponds to the image index that contains the label.
        """
        classes = self.dataset.metainfo.get('classes', None)
        if classes is None:
            raise ValueError('dataset metainfo must contain `classes`')
        # sort the label index
        cat2imgs = {i: [] for i in range(len(classes))}
        for i in range(len(self.dataset)):
            cat_ids = set(self.dataset.get_cat_ids(i))
            for cat in cat_ids:
                cat2imgs[cat].append(i)
        return cat2imgs

    def __iter__(self) -> Iterator[int]:
        # deterministically shuffle based on epoch
        g = torch.Generator()
        g.manual_seed(self.epoch + self.seed)

        # initialize label list
        label_iter_list = RandomCycleIter(self.valid_cat_inds, generator=g)
        # initialize each per-label image list
        data_iter_dict = dict()
        for i in self.valid_cat_inds:

View on GitHub (pinned to cfd5d3a985)

Solutions

  1. Give the dataset a metainfo containing classes, e.g. metainfo=dict(classes=...) or define METAINFO in your dataset subclass using mmdet's CocoDetClasses
  2. Ensure the sampler wraps the leaf detection dataset (like CocoDataset) rather than a wrapper that strips metainfo
  3. Pass metainfo explicitly through the dataset config: dataset=dict(type='MyDataset', metainfo=dict(classes=[...]), ...)

Example fix

# before
dataset = dict(type='MyDetDataset', ...)  # no classes in metainfo
sampler = dict(type='ClassAwareSampler', num_sample_class=1, cls_loss_weight=1.0)
# after
from mmdet.datasets import CocoDetClasses
dataset = dict(type='MyDetDataset', metainfo=dict(classes=CocoDetClasses), ...)
Defensive patterns

Strategy: validation

Validate before calling

metainfo = dataset.metainfo
assert 'classes' in metainfo and metainfo['classes'], 'dataset metainfo lacks classes; required by ClassAwareSampler'

Type guard

def has_classes_metainfo(ds) -> bool:
    return bool(getattr(ds, 'metainfo', {}).get('classes'))

Prevention

When it happens

Trigger: Constructing ClassAwareSampler over a dataset whose METAINFO lacks 'classes' — e.g. wrapping ConcatDataset/CustomDataset without category definitions, a video/tracking dataset, or a plain mmengine BaseDataset with no metainfo merge.

Common situations: Using ClassAwareSampler with a custom dataset class that forgets to define METAINFO with classes, wrapping datasets in ClassBalancedDataset (double wrapping) that hides metainfo, or version upgrades where metainfo propagation changed.

Related errors


AI-assisted analysis of open-mmlab/mmdetection@cfd5d3a985 (2026-08-27). Data as JSON: /api/errors/d4976e626afae685. Report an issue: GitHub.