roboflow/supervision · error · TypeError

Value must be a np.ndarray or a list

Error message

Value must be a np.ndarray or a list

What it means

F1Score's kernel computes F1 = 2TP / (2TP + FP + FN) from an array whose last axis must be exactly 3 (TP, FP, FN). The guard rejects arrays whose final dimension differs — e.g. square class-confusion matrices or two-column tallies — protecting the arithmetic from silently wrong indexing.

Source

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

            from supervision import _cv2 as cv2
            import supervision as sv
            from ultralytics import YOLO

            image = cv2.imread("<SOURCE_IMAGE_PATH>")
            model = YOLO('yolov8s.pt')

            result = model(image)[0]
            key_points = sv.KeyPoints.from_ultralytics(result)

            key_points['class_name'] = [
                 model.model.names[class_id]
                 for class_id
                 in key_points.class_id
             ]
            ```
        """
        if not isinstance(value, (np.ndarray, list)):
            raise TypeError("Value must be a np.ndarray or a list")

        if isinstance(value, list):
            value = np.array(value)

        self.data[key] = value

    @classmethod
    def empty(cls) -> KeyPoints:
        """
        Create an empty KeyPoints object with no key points.

        Returns:
            An empty `sv.KeyPoints` object.

        Examples:
            ```pycon
            >>> import supervision as sv
            >>> key_points = sv.KeyPoints.empty()

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Build a (N, ..., 3) array: np.stack([tp, fp, fn], axis=-1)
  2. Derive TP/FP/FN from a square matrix first (diagonal = TP, off-diagonal column/row sums = FP/FN) if that is what you have
  3. Use the public sv.F1Score API instead of the internal helper

Example fix

# before
f1_score(cm.matrix)  # square matrix -> ValueError

# after
tp = np.diag(cm.matrix).astype(np.float64)
fp = cm.matrix.sum(axis=0) - tp
fn = cm.matrix.sum(axis=1) - tp
f1_score(np.stack([tp, fp, fn], axis=-1))  # (num_classes, 3)
Defensive patterns

Strategy: validation

Validate before calling

def to_stats(tp, fp, fn) -> np.ndarray:
    tp, fp, fn = (np.asarray(x, dtype=np.float64) for x in (tp, fp, fn))
    assert tp.shape == fp.shape == fn.shape
    return np.stack([tp, fp, fn], axis=-1)  # (..., 3)

assert to_stats(tp, fp, fn).shape[-1] == 3

Type guard

def is_tpfpfn_array(arr: np.ndarray) -> bool:
    """True when the last axis holds exactly [TP, FP, FN]."""
    return isinstance(arr, np.ndarray) and arr.ndim >= 1 and arr.shape[-1] == 3

Prevention

When it happens

Trigger: Passing a sv.ConfusionMatrix's (num_classes+1, num_classes+1) matrix, or a hand-built [TP, FP] array, to the module-level f1_score helper. Normally unreachable through sv.F1Score's public API, which constructs the 3-column stats itself.

Common situations: Importing internal helpers to compute F1 from a stored confusion matrix; misunderstanding that 'confusion matrix' here denotes the per-item TP/FP/FN tally.

Related errors


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