{"record":{"id":"d90f413bfa6bb5d3","repo":"roboflow/supervision","slug":"results-must-be-a-list","errorCode":null,"errorMessage":"results must be a list","messagePattern":"results must be a list","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/metrics/mean_average_precision.py","lineNumber":521,"sourceCode":"            return []\n        return [self.anns[idx] for idx in ids]\n\n    def load_predictions(self, predictions: list[_TypeCocoDict]) -> EvaluationDataset:\n        \"\"\"\n        Load prediction result into an EvaluationDataset object.\n\n        Args:\n            predictions: prediction result.\n\n        Returns:\n            EvaluationDataset object representing the predictions.\n        \"\"\"\n        # Create an empty EvaluationDataset object for the predictions\n        predictions_dataset = EvaluationDataset.empty()\n        predictions_dataset.dataset[\"images\"] = list(self.dataset[\"images\"])\n\n        if not isinstance(predictions, list):\n            raise ValueError(\"results must be a list\")\n\n        # Handle empty predictions\n        if len(predictions) == 0:\n            predictions_dataset.dataset[\"annotations\"] = []\n            return predictions_dataset\n\n        ids = [pred[\"image_id\"] for pred in predictions]\n\n        # Make sure the image ids from predictions exist in the current dataset.\n        # A plain ``assert`` would be stripped under ``python -O``, so validate\n        # this public-input contract with an explicit exception instead.\n        if not set(ids) <= set(self.get_image_ids()):\n            raise ValueError(\"Results do not correspond to current coco set\")\n\n        # Check if the predictions contain any unsupported keys\n        if \"caption\" in predictions[0]:\n            raise NotImplementedError(\n                \"Evaluating predictions with caption is not supported.\"","sourceCodeStart":503,"sourceCodeEnd":539,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/metrics/mean_average_precision.py#L503-L539","documentation":"EvaluationDataset.load_predictions() (the COCO-format evaluation path used by MeanAveragePrecision's COCO backend) requires its predictions argument to already be a list of COCO-style result dicts. Unlike the Detections-facing update() path, it does not auto-wrap single objects; this ValueError fires when predictions is not a list instance. The comment-free contract: pass a list (possibly empty) of dicts with keys like image_id, category_id, bbox, score.","triggerScenarios":"Calling EvaluationDataset.load_predictions(single_dict) or load_predictions(tuple(generator)) or a numpy array of dicts; passing a COCO-results JSON object (a dict of lists) instead of the list itself; calling the COCO-evaluator API directly instead of going through MeanAveragePrecision.update().","commonSituations":"json.load of a COCO results file yields a list but users sometimes wrap or transform it; using pandas itertuples/tuple outputs; migrating code that mixed torchmetrics/supervision COCO APIs; calling internal evaluation APIs while integrating custom pipelines.","solutions":["Pass a list: load_predictions(list(predictions))","If you have a single prediction dict, wrap it: load_predictions([pred])","For COCO JSON files, load and pass the top-level array: results = json.load(f); load_predictions(results)","Prefer the public MeanAveragePrecision.update(preds, targets) with Detections, which normalizes input shapes itself"],"exampleFix":"# before\npreds = {'image_id': 1, 'category_id': 2, 'bbox': [...], 'score': 0.9}\ndataset.load_predictions(preds)  # dict, not list\n\n# after\npreds = [{'image_id': 1, 'category_id': 2, 'bbox': [...], 'score': 0.9}]\ndataset.load_predictions(preds)","handlingStrategy":"type-guard","validationCode":"if not isinstance(predictions, list):\n    predictions = [predictions] if isinstance(predictions, dict) else list(predictions)\ndataset.load_predictions(predictions)","typeGuard":"from typing import Any, List, Dict\n\ndef is_prediction_list(value: Any) -> bool:\n    \"\"\"True when value is a list (possibly of COCO result dicts).\"\"\"\n    return isinstance(value, list)","tryCatchPattern":"try:\n    coco_det = dataset.load_predictions(results)\nexcept ValueError as e:\n    if 'must be a list' in str(e) and isinstance(results, dict):\n        coco_det = dataset.load_predictions([results])\n    else:\n        raise","preventionTips":["Always pass a list, even for one prediction","json.load of a COCO results file already yields a list — pass it unchanged","Prefer the public MeanAveragePrecision.update() API for Detections workflows"],"tags":["metrics","mean-average-precision","coco","validation","input-type"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}