roboflow/supervision · error · ValueError

2D boolean mask row count {mask.shape[0]} does not match obj

Error message

2D boolean mask row count {mask.shape[0]} does not match object count {n}.

What it means

F1Score._detections_content() mirrors Precision's: it extracts boxes, masks, or oriented boxes from Detections by metric target and raises for any MetricTarget beyond BOXES, MASKS, and ORIENTED_BOUNDING_BOXES. With the current enum the branch is unreachable defensive code that fails fast on unsupported/injected targets.

Source

Thrown at src/supervision/key_points/core.py:865

        Args:
            mask: A boolean array of shape `(n, m)` where `n` is the number of
                objects and `m` is the number of keypoints per object.  Every row
                must select the same number of keypoints so that the result can be
                stored in a uniform `(n, k, ...)` array.

        Returns:
            A new `KeyPoints` instance containing only the keypoints selected by
            the mask for each object.

        Raises:
            ValueError: If `mask.shape[0]` does not match the number of objects, if
                `mask.shape[1]` does not match the number of keypoints, or if
                different rows of the mask select different numbers of `True` values.
        """
        n = len(self.xy)
        if mask.shape[0] != n:
            raise ValueError(
                f"2D boolean mask row count {mask.shape[0]} does not match "
                f"object count {n}."
            )
        if mask.shape[1] != self.xy.shape[1]:
            raise ValueError(
                f"2D boolean mask column count {mask.shape[1]} does not match "
                f"keypoint count {self.xy.shape[1]}."
            )
        counts = np.sum(mask, axis=1)
        if n > 0 and not np.all(counts == counts[0]):
            raise ValueError(
                "Cannot filter keypoints with a 2D boolean mask where rows have "
                "different numbers of True values. "
                "All objects must select the same number of keypoints. "
                f"Got counts per object: {counts.tolist()}"
            )
        k = int(counts[0]) if n > 0 else 0
        xy_selected = np.zeros((n, k, self.xy.shape[2]), dtype=self.xy.dtype)

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Use a consistent, single supervision version across the project
  2. Use only BOXES, MASKS, or ORIENTED_BOUNDING_BOXES for F1Score
  3. Remove custom metric_target injections

Example fix

# before
f1 = sv.F1Score(metric_target=unsupported_target)  # -> ValueError on compute

# after
f1 = sv.F1Score(metric_target=sv.MetricTarget.BOXES)
Defensive patterns

Strategy: validation

Validate before calling

SUPPORTED = {sv.MetricTarget.BOXES, sv.MetricTarget.MASKS, sv.MetricTarget.ORIENTED_BOUNDING_BOXES}
assert target in SUPPORTED, 'F1Score does not support this metric target'

Type guard

def is_supported_f1_target(target: sv.MetricTarget) -> bool:
    return target in {sv.MetricTarget.BOXES, sv.MetricTarget.MASKS, sv.MetricTarget.ORIENTED_BOUNDING_BOXES}

Prevention

When it happens

Trigger: Constructing sv.F1Score(metric_target=<unsupported or future MetricTarget member>) in a version-skewed environment or with a patched enum, then calling update()/compute() with non-empty Detections.

Common situations: Mixed supervision versions after partial upgrades; custom enum values passed as metric_target.

Related errors


AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15). Data as JSON: /api/errors/87b5dc160b592e8c. Report an issue: GitHub.