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
- Wrap polygons per image: PolygonMasks([[poly1, poly2], [poly3]]) — outer list per image, inner list per instance
- Build from dataset dicts via detectron2's detected already-nested structures
- 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
- Normalize annotations to 3-level nesting before PolygonMasks
- Write dataset adapter tests with sample annotations
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
- Cannot create polygons: Expect a list of polygons per instan
- Cannot match one checkpoint key to multiple keys in the mode
- Class with @configurable must have a 'from_config' classmeth
- {name} must take 'cfg' as the first argument!
- target of LazyCall must be a callable or defines a callable!
AI-assisted analysis of facebookresearch/detectron2@a2f4a8771a (2026-08-27).
Data as JSON: /api/errors/ac5a0828ba65d265.
Report an issue: GitHub.