{"record":{"id":"4a3e46413a399e3c","repo":"facebookresearch/detectron2","slug":"cannot-create-polygons-expect-a-list-of-polygons","errorCode":null,"errorMessage":"Cannot create polygons: Expect a list of polygons per instance. Got '{}' instead.","messagePattern":"Cannot create polygons: Expect a list of polygons per instance\\. Got '(.+?)' instead\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"detectron2/structures/masks.py","lineNumber":300,"sourceCode":"            raise ValueError(\n                \"Cannot create PolygonMasks: Expect a list of list of polygons per image. \"\n                \"Got '{}' instead.\".format(type(polygons))\n            )\n\n        def _make_array(t: Union[torch.Tensor, np.ndarray]) -> np.ndarray:\n            # Use float64 for higher precision, because why not?\n            # Always put polygons on CPU (self.to is a no-op) since they\n            # are supposed to be small tensors.\n            # May need to change this assumption if GPU placement becomes useful\n            if isinstance(t, torch.Tensor):\n                t = t.cpu().numpy()\n            return np.asarray(t).astype(\"float64\")\n\n        def process_polygons(\n            polygons_per_instance: List[Union[torch.Tensor, np.ndarray]],\n        ) -> List[np.ndarray]:\n            if not isinstance(polygons_per_instance, list):\n                raise ValueError(\n                    \"Cannot create polygons: Expect a list of polygons per instance. \"\n                    \"Got '{}' instead.\".format(type(polygons_per_instance))\n                )\n            # transform each polygon to a numpy array\n            polygons_per_instance = [_make_array(p) for p in polygons_per_instance]\n            for polygon in polygons_per_instance:\n                if len(polygon) % 2 != 0 or len(polygon) < 6:\n                    raise ValueError(f\"Cannot create a polygon from {len(polygon)} coordinates.\")\n            return polygons_per_instance\n\n        self.polygons: List[List[np.ndarray]] = [\n            process_polygons(polygons_per_instance) for polygons_per_instance in polygons\n        ]\n\n    def to(self, *args: Any, **kwargs: Any) -> \"PolygonMasks\":\n        return self\n\n    @property","sourceCodeStart":282,"sourceCodeEnd":318,"githubUrl":"https://github.com/facebookresearch/detectron2/blob/a2f4a8771ab77e8411c26b27f24f9489a28a2453/detectron2/structures/masks.py#L282-L318","documentation":"Inside PolygonMasks construction, each entry must itself be a list of polygons for one instance. Passing e.g. a numpy array of shape (N, 2) or a flat coordinate array for one instance fails the list check in process_polygons.","triggerScenarios":"PolygonMasks([[np.array([x0,y0,...])]]) is fine, but PolygonMasks([[np.array((N,2))]]) or an array-of-arrays per instance triggers it: any non-list per-instance value raises.","commonSituations":"Annotating with a single numpy array of polygon vertices per instance (common with cv2.findContours output) instead of a list of coordinate arrays.","solutions":["Wrap each instance's polygons in a list: [np.array([x0,y0,x1,y1,...])]","Convert contour output: [contour.flatten() for contour in contours]","Validate nesting depth (3 levels) before constructing PolygonMasks"],"exampleFix":"# before\nmasks = PolygonMasks([[contour_array]])  # contour_array shape (N,2)\n# after\nmasks = PolygonMasks([[[pt[0], pt[1]] for pt in contour_array]])","handlingStrategy":"validation","validationCode":"assert all(isinstance(inst, list) for inst in polygons), 'each instance must be a list of polygon arrays'","typeGuard":"def is_valid_per_instance(p) -> bool:\n    return isinstance(p, list) and all(hasattr(poly, '__len__') for poly in p)","tryCatchPattern":null,"preventionTips":["Wrap per-instance polygon arrays in lists","Flatten cv2 contours to [x0,y0,x1,y1,...] arrays before packing"],"tags":["detectron2","polygon-masks","annotation-format"],"backgroundTag":"invalid-data-structure-format","analyzedSha":"a2f4a8771ab77e8411c26b27f24f9489a28a2453","analyzedAt":"2026-08-27T12:08:21.260Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}