roboflow/supervision · error · ValueError
Could not create image tiles from empty list of images.
Error message
Could not create image tiles from empty list of images.
What it means
Raised by `sv.create_tiles` when the `images` list is empty. Building a grid of tiles from zero images has no meaningful result (no width, height, or grid size can be negotiated), so the function rejects the input early with a clear message instead of failing inside numpy/OpenCV.
Source
Thrown at src/supervision/utils/image.py:840
titles_thickness: Thickness of title text.
titles_padding: Size of title padding.
titles_text_font: Font used to render titles. Must be an integer
constant representing an OpenCV font.
(See docs: https://docs.opencv.org/4.x/d6/d6e/group__imgproc__draw.html)
titles_background_color: Color of the title text padding.
default_title_placement: Title anchor placement used when an explicit
anchor is not provided.
Returns:
ImageType: Image with all input images located in tiles grid. The output type is
determined by `return_type` parameter.
Raises:
ValueError: In case when input images list is empty, provided `grid_size` is too
small to fit all images, `tile_scaling` mode is invalid.
"""
if len(images) == 0:
raise ValueError("Could not create image tiles from empty list of images.")
if return_type == "auto":
return_type = _negotiate_tiles_format(images=images)
tile_padding_color = unify_to_bgr(color=tile_padding_color)
tile_margin_color = unify_to_bgr(color=tile_margin_color)
images_cv2 = images_to_cv2(images=images)
if single_tile_size is None:
single_tile_size = _aggregate_images_shape(images=images_cv2, mode=tile_scaling)
resized_images = [
letterbox_image(
image=i, resolution_wh=single_tile_size, color=tile_padding_color
)
for i in images_cv2
]
grid_size = _establish_grid_size(images=images_cv2, grid_size=grid_size)
if len(images_cv2) > grid_size[0] * grid_size[1]:
raise ValueError(
f"Could not place {len(images_cv2)} in grid with size: {grid_size}."
)View on GitHub (pinned to 7f254d9784)
Solutions
- Guard the call: `if crops: montage = sv.create_tiles(images=crops)`.
- Check the upstream filter — if everything was filtered out, your threshold or mask may be wrong.
- For batch jobs, skip empty groups and log them instead of calling create_tiles.
Example fix
# before montage = sv.create_tiles(images=[crop for crop in crops if crop.area > 0.1]) # may be [] # after crops = [crop for crop in crops if crop.area > 0.1] montage = sv.create_tiles(images=crops) if crops else None
Defensive patterns
Strategy: validation
Validate before calling
assert len(images) > 0, 'cannot build tiles from zero images'
Type guard
def has_images(images: list) -> bool:
return len(images) > 0 Prevention
- Guard create_tiles with `if images:` at call sites.
- Log when filters produce zero crops — often a threshold bug.
- In batch loops over folders, skip empty groups explicitly.
When it happens
Trigger: Passing `[]` directly; passing the result of a filter/list comprehension that removed every element (e.g. all detections below threshold, so no crops were collected); an early-morning batch where the first folder is empty.
Common situations: Visualizing top-k detection crops when the model found nothing; aggregating frames from a queue that was drained; looping over directories where some contain zero images.
Related errors
- COCO RLE counts cannot be empty.
- Input mask cannot be empty
- Scale factor must be positive.
- opacity must be between 0.0 and 1.0
- Could not place {len(images_cv2)} in grid with size: {grid_s
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/1bdaa609a9eb2f26.
Report an issue: GitHub.