{"record":{"id":"715ca2abd259d160","repo":"roboflow/supervision","slug":"the-number-of-predictions-len-predictions-and","errorCode":null,"errorMessage":"The number of predictions ({len(predictions)}) and targets ({len(targets)}) during the update must be the same.","messagePattern":"The number of predictions \\((.+?)\\) and targets \\((.+?)\\) during the update must be the same\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/metrics/mean_average_recall.py","lineNumber":355,"sourceCode":"        targets: Detections | list[Detections],\n    ) -> MeanAverageRecall:\n        \"\"\"\n        Add new predictions and targets to the metric, but do not compute the result.\n\n        Args:\n            predictions: The predicted detections.\n            targets: The target detections.\n\n        Returns:\n            The updated metric instance.\n        \"\"\"\n        if not isinstance(predictions, list):\n            predictions = [predictions]\n        if not isinstance(targets, list):\n            targets = [targets]\n\n        if len(predictions) != len(targets):\n            raise ValueError(\n                f\"The number of predictions ({len(predictions)}) and\"\n                f\" targets ({len(targets)}) during the update must be the same.\"\n            )\n\n        self._predictions_list.extend(predictions)\n        self._targets_list.extend(targets)\n\n        return self\n\n    def compute(self) -> MeanAverageRecallResult:\n        \"\"\"\n        Calculate the Mean Average Recall metric based on the stored predictions\n        and ground-truth, at different IoU thresholds and maximum detection counts.\n\n        Returns:\n            The Mean Average Recall metric result.\n        \"\"\"\n        result = self._compute(self._predictions_list, self._targets_list)","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/metrics/mean_average_recall.py#L337-L373","documentation":"MeanAverageRecall.update() accepts either a single Detections or a list of Detections for predictions and targets, but the two arguments must describe the same images. This ValueError fires when, after list-wrapping, len(predictions) != len(targets) — i.e. you passed a different number of prediction frames than ground-truth frames. The metric pairs them index-by-index, so a mismatch would silently misalign evaluations, hence the hard failure.","triggerScenarios":"Calling mar.update([pred1, pred2], [target1]) or mar.update(preds_list, targets_list) where the lists have different lengths; wrapping only one side in a list (update([p], t) on a non-empty target with empty predictions list vs single Detections); accumulating predictions in a loop but appending targets only on some frames.","commonSituations":"Streaming video frames where the model skips frames (NVR dropout, inference exceptions swallowed) so prediction list grows slower than targets; batching predictions per image but passing all targets as one Detections; off-by-one when appending the first/last frame.","solutions":["Ensure both arguments are lists of equal length, one entry per image: mar.update(list_of_preds, list_of_targets) with len equal","If a frame has no predictions, still pass an empty sv.Detections.empty() placeholder so indexes stay aligned","Audit accumulation loops: append to both lists in the same iteration, never conditionally to one","Add an assert len(preds)==len(targets) before update() in pipeline code to fail at the call site with your own context"],"exampleFix":"# before\nfor frame in frames:\n    preds.append(model(frame))\n    if frame.has_annotation:  # targets appended conditionally -> length drift\n        targets.append(frame.targets)\nmar.update(preds, targets)\n\n# after\nfor frame in frames:\n    preds.append(model(frame))\n    targets.append(frame.targets if frame.has_annotation else sv.Detections.empty())\nassert len(preds) == len(targets)\nmar.update(preds, targets)","handlingStrategy":"validation","validationCode":"from supervision.detection.core import Detections\n\ndef safe_update(mar, preds, tgts):\n    \"\"\"Update MAR only when per-image counts align.\"\"\"\n    preds = preds if isinstance(preds, list) else [preds]\n    tgts = tgts if isinstance(tgts, list) else [tgts]\n    if len(preds) != len(tgts):\n        raise ValueError(f'{len(preds)} preds vs {len(tgts)} targets')\n    return mar.update(preds, tgts)","typeGuard":"from typing import Union, List\nfrom supervision.detection.core import Detections\n\ndef is_paired_detection_lists(\n    preds: Union[Detections, List[Detections]],\n    tgts: Union[Detections, List[Detections]],\n) -> bool:\n    \"\"\"True when both sides normalize to equal-length per-image lists.\"\"\"\n    p = preds if isinstance(preds, list) else [preds]\n    t = tgts if isinstance(tgts, list) else [tgts]\n    return len(p) == len(t)","tryCatchPattern":null,"preventionTips":["Append predictions and targets in the same loop iteration","Use sv.Detections.empty() placeholders for frames with no detections","Assert equal lengths right before update()"],"tags":["metrics","mean-average-recall","validation","input-shape","api-misuse"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}