{"record":{"id":"712557aca8bac476","repo":"roboflow/supervision","slug":"corners-must-have-shape-n-4-2-got-corners-sh","errorCode":null,"errorMessage":"corners must have shape (N, 4, 2); got {corners.shape}","messagePattern":"corners must have shape \\(N, 4, 2\\); got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/detection/utils/boxes.py","lineNumber":272,"sourceCode":"    Returns:\n        Area of each box as a 1-D float64 array of shape `(N,)`.\n\n    Raises:\n        ValueError: If `corners` does not have shape `(N, 4, 2)`.\n\n    Examples:\n        ```pycon\n        >>> import numpy as np\n        >>> from supervision.detection.utils.boxes import obb_polygon_area\n        >>> corners = np.array([[[0, 5], [5, 10], [10, 5], [5, 0]]], dtype=np.float32)\n        >>> obb_polygon_area(corners)\n        array([50.])\n\n        ```\n    \"\"\"\n    corners = cast(npt.NDArray[np.number], np.asarray(corners))\n    if corners.ndim != 3 or corners.shape[-2:] != (4, 2):\n        raise ValueError(f\"corners must have shape (N, 4, 2); got {corners.shape}\")\n    x = corners[..., 0].astype(np.float64, copy=False)\n    y = corners[..., 1].astype(np.float64, copy=False)\n    cross = x * np.roll(y, -1, axis=-1) - y * np.roll(x, -1, axis=-1)\n    return cast(npt.NDArray[np.float64], 0.5 * np.abs(np.sum(cross, axis=-1)))\n\n\ndef xyxyxyxy_to_xyxy(\n    xyxyxyxy: npt.NDArray[np.number],\n) -> npt.NDArray[np.number]:\n    \"\"\"Convert oriented bounding box corners to axis-aligned bounding boxes.\n\n    Args:\n        xyxyxyxy: OBB corner coordinates with shape `(N, 4, 2)` where each\n            box is represented as `[[x1, y1], [x2, y2], [x3, y3], [x4, y4]]`.\n\n    Returns:\n        Axis-aligned bounding boxes as an array of shape `(N, 4)`\n            in `(x_min, y_min, x_max, y_max)` format.","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/detection/utils/boxes.py#L254-L290","documentation":"Raised by obb_polygon_area when the corners array is not shaped (N, 4, 2): N oriented boxes, each with exactly 4 corner points, each point with x and y. The shoelace-area computation indexes the last two axes directly, so any other shape would compute garbage or broadcast incorrectly, hence the strict check.","triggerScenarios":"Calling obb_polygon_area with a single box of shape (4, 2) (missing the batch axis), a list that assembles to (N, 4) or (N, 2, 4), a ragged list of corners, or a 2-D axis-aligned xyxy array of shape (N, 4).","commonSituations":"Forgetting np.array([corners]) around a single box; transposed corner arrays coming out of a custom OBB decoder; feeding xyxy boxes into an oriented-box helper by mistake.","solutions":["Wrap a single box in a batch axis: corners = corners[np.newaxis, :] so the shape becomes (1, 4, 2).","If corners are transposed (N, 2, 4), transpose before calling: corners.transpose(0, 2, 1).","Ensure each of the N entries has exactly 4 (x, y) points; re-serialize the source data if some boxes have a different corner count."],"exampleFix":"# before\ncorners = np.array([[0, 5], [5, 10], [10, 5], [5, 0]], dtype=np.float32)\nobb_polygon_area(corners)  # ValueError: shape is (4, 2)\n\n# after\ncorners = np.array([[[0, 5], [5, 10], [10, 5], [5, 0]]], dtype=np.float32)\nobb_polygon_area(corners)  # array([50.])","handlingStrategy":"type-guard","validationCode":"import numpy as np\n\ndef as_obb_corners(a) -> np.ndarray:\n    a = np.asarray(a, dtype=np.float64)\n    if a.ndim == 2 and a.shape == (4, 2):\n        a = a[np.newaxis]\n    assert a.ndim == 3 and a.shape[-2:] == (4, 2), f'bad corners shape {a.shape}'\n    return a\n\narea = obb_polygon_area(as_obb_corners(corners))","typeGuard":"def is_obb_corners(a) -> bool:\n    a = np.asarray(a)\n    return a.ndim == 3 and a.shape[-2:] == (4, 2)","tryCatchPattern":null,"preventionTips":["Keep a single project-wide helper that coerces OBB arrays to (N, 4, 2) before any oriented-box API.","Reshape flattened 8-value OBB outputs with .reshape(-1, 4, 2) at the model boundary."],"tags":["oriented-bounding-box","numpy","shape-validation","valueerror"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}