roboflow/supervision · error · ValueError

Could not place {len(images_cv2)} in grid with size: {grid_s

Error message

Could not place {len(images_cv2)} in grid with size: {grid_size}.

What it means

Raised by `sv.create_tiles` when the resolved `grid_size` (rows x cols) cannot hold all images — i.e. `len(images) > rows * cols`. This only happens when you pass an explicit `grid_size` that is too small; with `grid_size=None` the function auto-negotiates a size that fits.

Source

Thrown at src/supervision/utils/image.py:856

    """
    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}."
        )
    if titles is not None:
        titles = fill(sequence=titles, desired_size=len(images_cv2), content=None)
    if isinstance(titles_anchors, list):
        titles_anchors_sequence = titles_anchors
    else:
        titles_anchors_sequence = [titles_anchors]
    titles_anchors = fill(
        sequence=titles_anchors_sequence, desired_size=len(images_cv2), content=None
    )
    titles_color = unify_to_bgr(color=titles_color)
    titles_background_color = unify_to_bgr(color=titles_background_color)
    tiles_image = _generate_tiles(
        images=resized_images,
        grid_size=grid_size,
        single_tile_size=single_tile_size,
        tile_padding_color=tile_padding_color,

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Pass `grid_size=None` and let supervision compute a fitting grid.
  2. Or compute it: `cols = math.ceil(math.sqrt(len(images))); grid_size=(math.ceil(len(images)/cols), cols)`.
  3. Double the intended order — verify whether your tuple is (rows, cols) as expected.

Example fix

# before
montage = sv.create_tiles(images=images_10, grid_size=(2, 2))
# after
montage = sv.create_tiles(images=images_10, grid_size=None)  # auto-fit
Defensive patterns

Strategy: validation

Validate before calling

if grid_size is not None:
    rows, cols = grid_size
    assert rows * cols >= len(images), f'grid {grid_size} too small for {len(images)} images'

Type guard

def grid_fits(grid_size: tuple[int, int], n: int) -> bool:
    rows, cols = grid_size
    return rows * cols >= n

Prevention

When it happens

Trigger: `sv.create_tiles(images=[im]*10, grid_size=(2, 2))` — 10 images into a 2x2 grid; passing a fixed grid tuned for an earlier, smaller batch; passing columns only (e.g. `(2, None)`) where the computed rows are insufficient.

Common situations: Hard-coding grid dimensions for a fixed number of camera feeds, then adding a feed; visualizing a variable number of crops with a constant grid; confusing (rows, cols) order so the product looks larger than it is.

Related errors


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