facebookresearch/detectron2 · error · ValueError

Cannot create PolygonMasks: Expect a list of list of polygon

Error message

Cannot create PolygonMasks: Expect a list of list of polygons per image. Got '{}' instead.

What it means

PolygonMasks expects a 3-level list structure: per image a list of instances, each a list of polygon arrays. Passing a numpy array, tensor, or flattened list of polygons at the top level fails the isinstance(polygons, list) check.

Source

Thrown at detectron2/structures/masks.py:282

    """
    This class stores the segmentation masks for all objects in one image, in the form of polygons.

    Attributes:
        polygons: list[list[ndarray]]. Each ndarray is a float64 vector representing a polygon.
    """

    def __init__(self, polygons: List[List[Union[torch.Tensor, np.ndarray]]]):
        """
        Arguments:
            polygons (list[list[np.ndarray]]): The first
                level of the list correspond to individual instances,
                the second level to all the polygons that compose the
                instance, and the third level to the polygon coordinates.
                The third level array should have the format of
                [x0, y0, x1, y1, ..., xn, yn] (n >= 3).
        """
        if not isinstance(polygons, list):
            raise ValueError(
                "Cannot create PolygonMasks: Expect a list of list of polygons per image. "
                "Got '{}' instead.".format(type(polygons))
            )

        def _make_array(t: Union[torch.Tensor, np.ndarray]) -> np.ndarray:
            # Use float64 for higher precision, because why not?
            # Always put polygons on CPU (self.to is a no-op) since they
            # are supposed to be small tensors.
            # May need to change this assumption if GPU placement becomes useful
            if isinstance(t, torch.Tensor):
                t = t.cpu().numpy()
            return np.asarray(t).astype("float64")

        def process_polygons(
            polygons_per_instance: List[Union[torch.Tensor, np.ndarray]],
        ) -> List[np.ndarray]:
            if not isinstance(polygons_per_instance, list):
                raise ValueError(

View on GitHub (pinned to a2f4a8771a)

Solutions

  1. Wrap polygons per image: PolygonMasks([[poly1, poly2], [poly3]]) — outer list per image, inner list per instance
  2. Build from dataset dicts via detectron2's detected already-nested structures
  3. Convert numpy/tensor inputs to the nested list form first

Example fix

# before
masks = PolygonMasks(np.array([poly1, poly2]))
# after
masks = PolygonMasks([[poly1, poly2]])
Defensive patterns

Strategy: validation

Validate before calling

assert isinstance(polygons, list) and all(isinstance(img, list) for img in polygons), 'PolygonMasks expects list[list[polygon-array]]'

Type guard

def is_valid_polygon_list(p) -> bool:
    return isinstance(p, list) and all(isinstance(inst, list) for inst in p)

Try / catch

try:
    masks = PolygonMasks(polygons)
except ValueError as e:
    raise ValueError(f'Bad polygon structure: {e}') from e

Prevention

When it happens

Trigger: PolygonMasks(np.array([...])) or PolygonMasks([poly1, poly2]) instead of PolygonMasks([[poly1, poly2]]); converting from COCO anns without grouping per image.

Common situations: Loading DOTA/COCO-style annotations and passing polygons directly instead of the per-image nested list; version-0-era code relying on looser inputs.

Related errors


AI-assisted analysis of facebookresearch/detectron2@a2f4a8771a (2026-08-27). Data as JSON: /api/errors/ac5a0828ba65d265. Report an issue: GitHub.