{"record":{"id":"3206c2e7dee9cae2","repo":"roboflow/supervision","slug":"unsupported-metric-target-for-iou-calculation-3206c2","errorCode":null,"errorMessage":"Unsupported metric target for IoU calculation","messagePattern":"Unsupported metric target for IoU calculation","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/metrics/f1_score.py","lineNumber":262,"sourceCode":"                    prediction_confidence = np.asarray(\n                        predictions.confidence, dtype=np.float32\n                    )\n                    if self._metric_target == MetricTarget.BOXES:\n                        # BOXES target never yields CompactMask; narrow for mypy.\n                        iou = box_iou_batch(\n                            cast(npt.NDArray[np.number], target_contents),\n                            cast(npt.NDArray[np.number], prediction_contents),\n                        )\n                    elif self._metric_target == MetricTarget.MASKS:\n                        iou = mask_iou_batch(target_contents, prediction_contents)\n                    elif self._metric_target == MetricTarget.ORIENTED_BOUNDING_BOXES:\n                        # OBB target never yields CompactMask; narrow for mypy.\n                        iou = oriented_box_iou_batch(\n                            cast(npt.NDArray[np.number], target_contents),\n                            cast(npt.NDArray[np.number], prediction_contents),\n                        )\n                    else:\n                        raise ValueError(\n                            \"Unsupported metric target for IoU calculation\"\n                        )\n\n                    # None keeps the matcher on its single-round fast path\n                    # when no size bucket is scored.\n                    target_scored_mask = (\n                        target_size_mask\n                        if size_category != ObjectSizeCategory.ANY\n                        else None\n                    )\n                    matches, matched_target_indices = (\n                        _match_detection_batch_with_target_indices(\n                            prediction_class_ids,\n                            target_class_ids,\n                            iou,\n                            iou_thresholds,\n                            target_scored_mask=target_scored_mask,\n                        )","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/metrics/f1_score.py#L244-L280","documentation":"Defensive unreachable branch in F1Score's IoU computation: the code handles MetricTarget.BOXES, MASKS, and ORIENTED_BOUNDING_BOXES, and raises if _metric_target is anything else. With the current MetricTarget enum this cannot fire; it exists so that a future enum member added without an IoU strategy fails loudly instead of silently falling through with None. Hitting it means you passed an invalid/extended metric_target value.","triggerScenarios":"Constructing F1Score(metric_target=cast_value) with a value not in MetricTarget (e.g. an int outside the enum, or a monkeypatched/new enum member from a mismatched supervision version).","commonSituations":"Passing metric_target as a raw string or int instead of the MetricTarget enum; mixing supervision versions where a custom MetricTarget member was added on one side; dynamic target selection from config that yields an invalid value.","solutions":["Use the enum: from supervision.metrics.metric_target import MetricTarget; F1Score(metric_target=MetricTarget.BOXES)","Validate the value against MetricTarget before constructing the metric when it comes from external config"],"exampleFix":"# before\nf1 = sv.metrics.f1_score.F1Score(metric_target=3)  # invalid raw value\n\n# after\nfrom supervision.metrics.metric_target import MetricTarget\n\nf1 = sv.metrics.f1_score.F1Score(metric_target=MetricTarget.MASKS)","handlingStrategy":"type-guard","validationCode":"from supervision.metrics.metric_target import MetricTarget\n\nassert metric_target in (\n    MetricTarget.BOXES,\n    MetricTarget.MASKS,\n    MetricTarget.ORIENTED_BOUNDING_BOXES,\n), f'unsupported metric_target: {metric_target!r}'","typeGuard":"from supervision.metrics.metric_target import MetricTarget\n\nSUPPORTED_F1_TARGETS = frozenset({\n    MetricTarget.BOXES,\n    MetricTarget.MASKS,\n    MetricTarget.ORIENTED_BOUNDING_BOXES,\n})\n\ndef is_supported_target(t: object) -> bool:\n    \"\"\"True when t is a MetricTarget F1Score can compute IoU for.\"\"\"\n    return t in SUPPORTED_F1_TARGETS","tryCatchPattern":"try:\n    f1 = F1Score(metric_target=metric_target)\n    f1.update(targets=t, predictions=p)\nexcept ValueError as e:\n    if 'Unsupported metric target' in str(e):\n        f1 = F1Score(metric_target=MetricTarget.BOXES)  # explicit fallback choice\n    else:\n        raise","preventionTips":["Always pass MetricTarget enum members, never raw strings or ints","When loading metric_target from config, validate with MetricTarget(value) inside try/except at load time"],"tags":["metrics","f1-score","enum","unreachable-guard"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}