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

  1. Guard the call: `if crops: montage = sv.create_tiles(images=crops)`.
  2. Check the upstream filter — if everything was filtered out, your threshold or mask may be wrong.
  3. 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

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


AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15). Data as JSON: /api/errors/1bdaa609a9eb2f26. Report an issue: GitHub.