{"record":{"id":"dd355cf849079b4f","repo":"open-mmlab/mmdetection","slug":"metric-should-be-one-of-recall-map-but-got","errorCode":null,"errorMessage":"metric should be one of 'recall', 'mAP', but got {metric}.","messagePattern":"metric should be one of 'recall', 'mAP', but got (.+?)\\.","errorType":"validation","errorClass":"KeyError","httpStatus":null,"severity":"error","filePath":"mmdet/evaluation/metrics/voc_metric.py","lineNumber":64,"sourceCode":"    def __init__(self,\n                 iou_thrs: Union[float, List[float]] = 0.5,\n                 scale_ranges: Optional[List[tuple]] = None,\n                 metric: Union[str, List[str]] = 'mAP',\n                 proposal_nums: Sequence[int] = (100, 300, 1000),\n                 eval_mode: str = '11points',\n                 collect_device: str = 'cpu',\n                 prefix: Optional[str] = None) -> None:\n        super().__init__(collect_device=collect_device, prefix=prefix)\n        self.iou_thrs = [iou_thrs] if isinstance(iou_thrs, float) \\\n            else iou_thrs\n        self.scale_ranges = scale_ranges\n        # voc evaluation metrics\n        if not isinstance(metric, str):\n            assert len(metric) == 1\n            metric = metric[0]\n        allowed_metrics = ['recall', 'mAP']\n        if metric not in allowed_metrics:\n            raise KeyError(\n                f\"metric should be one of 'recall', 'mAP', but got {metric}.\")\n        self.metric = metric\n        self.proposal_nums = proposal_nums\n        assert eval_mode in ['area', '11points'], \\\n            'Unrecognized mode, only \"area\" and \"11points\" are supported'\n        self.eval_mode = eval_mode\n\n    # TODO: data_batch is no longer needed, consider adjusting the\n    #  parameter position\n    def process(self, data_batch: dict, data_samples: Sequence[dict]) -> None:\n        \"\"\"Process one batch of data samples and predictions. The processed\n        results should be stored in ``self.results``, which will be used to\n        compute the metrics when all batches have been processed.\n\n        Args:\n            data_batch (dict): A batch of data from the dataloader.\n            data_samples (Sequence[dict]): A batch of data samples that\n                contain annotations and predictions.","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/open-mmlab/mmdetection/blob/cfd5d3a985b0249de009b67d04f37263e11cdf3d/mmdet/evaluation/metrics/voc_metric.py#L46-L82","documentation":"VOCMetric only implements two metrics, 'recall' (proposal recall) and 'mAP'; any other string raises this KeyError in __init__. If metric is a non-str iterable it must have exactly one element, which is then used.","triggerScenarios":"Passing metric='AP50', metric=['mAP','recall'] (list of two, fails the len==1 assert), or metric='map' (lowercase) to VOCMetric.","commonSituations":"Confusing VOC 11-point/AP50 terminology with the two supported modes; passing a list where only a single metric is allowed; copy-pasting from CocoMetric configs that use lists.","solutions":["Use exactly one of 'mAP' or 'recall' (case-sensitive), e.g. metric='mAP'","If a list is used it must contain exactly one of those strings","Choose eval_mode ('area' or '11points') separately per VOC protocol, not via the metric name"],"exampleFix":"# before\nval_evaluator = dict(type='VOCMetric', metric=['AP50', 'mAP'], eval_mode='11points')\n# after\nval_evaluator = dict(type='VOCMetric', metric='mAP', eval_mode='11points')","handlingStrategy":"validation","validationCode":"assert metric in ('recall', 'mAP') or (not isinstance(metric, str) and len(metric) == 1 and metric[0] in ('recall', 'mAP'))","typeGuard":"def is_valid_voc_metric(metric) -> bool:\n    if isinstance(metric, (list, tuple)):\n        return len(metric) == 1 and metric[0] in ('recall', 'mAP')\n    return metric in ('recall', 'mAP')","tryCatchPattern":null,"preventionTips":["Use a single metric string 'mAP' or 'recall'","Lists must have exactly one element","Case-sensitive names"],"tags":["mmdet","voc","evaluation","config"],"backgroundTag":null,"analyzedSha":"cfd5d3a985b0249de009b67d04f37263e11cdf3d","analyzedAt":"2026-08-27T20:54:20.183Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}