{"record":{"id":"6331a8d90e30ebed","repo":"roboflow/supervision","slug":"polygon-must-have-at-least-one-vertex","errorCode":null,"errorMessage":"Polygon must have at least one vertex.","messagePattern":"Polygon must have at least one vertex\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/geometry/utils.py","lineNumber":41,"sourceCode":"    Examples:\n        ```pycon\n        >>> import numpy as np\n        >>> import supervision as sv\n        >>> polygon = np.array([[0, 0], [0, 2], [2, 2], [2, 0]])\n        >>> center = sv.get_polygon_center(polygon=polygon)\n        >>> float(center.x)\n        1.0\n        >>> float(center.y)\n        1.0\n\n        ```\n    \"\"\"\n\n    # This is one of the 3 candidate algorithms considered for centroid calculation.\n    # For a more detailed discussion, see PR #1084 and commit eb33176\n\n    if len(polygon) == 0:\n        raise ValueError(\"Polygon must have at least one vertex.\")\n\n    shift_polygon = np.roll(polygon, -1, axis=0)\n    signed_areas = (\n        polygon[..., 0] * shift_polygon[..., 1]\n        - polygon[..., 1] * shift_polygon[..., 0]\n    ) / 2\n    if signed_areas.sum() == 0:\n        center = np.mean(polygon, axis=0).round()\n        return Point(x=center[0], y=center[1])\n    centroids = (polygon + shift_polygon) / 3.0\n    center = np.average(centroids, axis=0, weights=signed_areas).round()\n\n    return Point(x=center[0], y=center[1])\n","sourceCodeStart":23,"sourceCodeEnd":55,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/geometry/utils.py#L23-L55","documentation":"The polygon centroid routine in src/supervision/geometry/utils.py:41 (shoelace-formula based, see PR #1084) requires at least one vertex; an empty polygon has no defined centroid. It raises ValueError before attempting any arithmetic so callers get a clear failure instead of NaN coordinates.","triggerScenarios":"Passing an empty `(0, 2)` array to `get_polygon_center` (or APIs that call it, e.g. `PolygonZone`/`PolygonAnnotator` with an empty polygon); passing a mask whose contour extraction returned zero points; slicing a polygon array with an index bug that yields an empty result.","commonSituations":"Building zones from user-drawn polygons where the user clicked zero times; `cv2.findContours` returning no contours on an all-black mask and forwarding the empty result; off-by-one slicing like `polygon[1:1]`.","solutions":["Check `len(polygon) > 0` before calling and skip/default when empty","Fix the upstream contour/point extraction so empty polygons are never forwarded","Validate polygon input at the UI/config boundary (require at least 3 points for a meaningful zone)"],"exampleFix":"// before\ncenter = get_polygon_center(np.array([], dtype=np.float32).reshape(0, 2))\n\n// after\npolygon = np.asarray(polygon, dtype=np.float32).reshape(-1, 2)\nif polygon.size == 0:\n    continue  # or raise a domain-specific error\ncenter = get_polygon_center(polygon)","handlingStrategy":"validation","validationCode":"import numpy as np\n\ndef has_vertices(polygon) -> bool:\n    \"\"\"Polygon centroid requires at least one (x, y) vertex.\"\"\"\n    return len(np.asarray(polygon).reshape(-1, 2)) > 0","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate zone polygons at input time (require >= 3 points for zones)","Guard contour-to-polygon code paths for empty findContours results"],"tags":["geometry","polygon","validation","numpy"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}