roboflow/supervision · error · ValueError
Cannot merge an empty list of CompactMask objects.
Error message
Cannot merge an empty list of CompactMask objects.
What it means
Raised by CompactMask.merge when masks_list is empty. Merging zero objects has no meaningful result (there is no image shape to inherit), so the API refuses rather than guessing. Pass at least one CompactMask.
Solutions
- Skip the merge when the list is empty: if not masks_list: continue / return an empty CompactMask built from the known image_shape.
- If detections were expected, debug why the producing step yielded no CompactMask objects before calling merge.
- Construct an empty result explicitly via CompactMask.from_dense(np.zeros((0, h, w), bool), np.empty((0, 4)), image_shape) when an empty object is needed.
Example fix
# before
merged = CompactMask.merge(tile_masks)
# after
if tile_masks:
merged = CompactMask.merge(tile_masks)
else:
merged = CompactMask.from_dense(
np.zeros((0, h, w), dtype=bool), np.empty((0, 4), dtype=np.float32),
image_shape=(h, w)) Defensive patterns
Strategy: validation
Validate before calling
if not tile_masks:
merged = sv.CompactMask.from_dense(
np.zeros((0, h, w), dtype=bool),
np.empty((0, 4), dtype=np.float32),
image_shape=(h, w),
)
else:
merged = sv.CompactMask.merge(tile_masks) Type guard
def is_mergeable(masks_list) -> bool:
return isinstance(masks_list, (list, tuple)) and len(masks_list) > 0 Try / catch
try:
merged = sv.CompactMask.merge(tile_masks)
except ValueError as e:
if "empty list" in str(e):
merged = None # nothing detected on any tile
else:
raise Prevention
- Guard merges behind `if masks_list:` whenever inputs come from detection loops that can yield zero results.
- Return a canonical empty CompactMask for the known image_shape instead of calling merge with [].
- Log the tile count before merging in slicer pipelines to notice all-empty batches.
When it happens
Trigger: Calling CompactMask.merge([]) — typically because a loop collecting per-tile or per-batch CompactMask objects produced an empty list (no detections anywhere, empty directory, all tiles filtered out).
Common situations: Aggregating slicer outputs when the model returned nothing on any tile; merging per-image masks in a loop over an empty folder; a guard upstream filtered everything.
Related errors
- Cannot merge CompactMask objects with different image shapes
- COCO RLE counts cannot be empty.
- new_image_shape must contain positive dimensions
- All data dictionaries must have the same keys to merge.
- All data values within a single object must have equal…
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/d70b42e0746470f7.
Report an issue: GitHub.
Appendix: source
Thrown at src/supervision/detection/compact_mask.py:1356
Examples:
```pycon
>>> import numpy as np
>>> from supervision.detection.compact_mask import CompactMask
>>> masks1 = np.zeros((2, 50, 50), dtype=bool)
>>> masks2 = np.zeros((3, 50, 50), dtype=bool)
>>> xyxy1 = np.array([[0,0,10,10],[10,10,20,20]], dtype=np.float32)
>>> xyxy2 = np.array(
... [[0,0,5,5],[5,5,10,10],[10,10,15,15]], dtype=np.float32)
>>> cm1 = CompactMask.from_dense(masks1, xyxy1, image_shape=(50, 50))
>>> cm2 = CompactMask.from_dense(masks2, xyxy2, image_shape=(50, 50))
>>> len(CompactMask.merge([cm1, cm2]))
5
```
"""
if not masks_list:
raise ValueError("Cannot merge an empty list of CompactMask objects.")
image_shape = masks_list[0]._image_shape
for cm in masks_list[1:]:
if cm._image_shape != image_shape:
raise ValueError(
f"Cannot merge CompactMask objects with different image shapes: "
f"{image_shape} vs {cm._image_shape}"
)
# list.extend is a C-level call and avoids the per-element Python
# bytecode overhead of a flat list comprehension. This matters under
# GIL contention when multiple threads call merge concurrently.
new_rles: list[npt.NDArray[np.int32]] = []
for cm in masks_list:
new_rles.extend(cm._rles)
# np.concatenate handles (0, 2) arrays correctly.
# No .astype() needed — _crop_shapes and _offsets are already int32.View on GitHub (pinned to 7f254d9784)