ultralytics/yolov5 · error · ValueError

"len of masks shape" should be 2 or 3, but got {len(masks.sh

Error message

"len of masks shape" should be 2 or 3, but got {len(masks.shape)}

What it means

Raised in scale_image (utils/segment/general.py) during segmentation post-processing when the masks tensor passed in has fewer than 2 dimensions. The rescale logic slices masks[top:bottom, left:right] and resizes with cv2.resize, both of which require at least a 2D (H, W) or 3D (H, W, N) array; a 0D scalar or 1D vector of masks cannot be spatially rescaled.

Source

Thrown at utils/segment/general.py:101

        im1_shape (tuple): Model input shape as (h, w).
        masks (np.ndarray): Masks with shape (h, w, num).
        im0_shape (tuple): Original image shape as (h, w, 3).
        ratio_pad (tuple, optional): Ratio and padding for scaling. If None, calculated from the shapes.

    Returns:
        (np.ndarray): Rescaled masks resized to im0_shape.
    """
    # Rescale coordinates (xyxy) from im1_shape to im0_shape
    if ratio_pad is None:  # calculate from im0_shape
        gain = min(im1_shape[0] / im0_shape[0], im1_shape[1] / im0_shape[1])  # gain  = old / new
        pad = (im1_shape[1] - im0_shape[1] * gain) / 2, (im1_shape[0] - im0_shape[0] * gain) / 2  # wh padding
    else:
        pad = ratio_pad[1]
    top, left = int(pad[1]), int(pad[0])  # y, x
    bottom, right = int(im1_shape[0] - pad[1]), int(im1_shape[1] - pad[0])

    if len(masks.shape) < 2:
        raise ValueError(f'"len of masks shape" should be 2 or 3, but got {len(masks.shape)}')
    masks = masks[top:bottom, left:right]
    if masks.ndim == 3 and masks.shape[2] > 128:  # OpenCV 5 lowered CV_CN_MAX from 512 to 128
        masks = [
            cv2.resize(masks[:, :, i : i + 128], (im0_shape[1], im0_shape[0])) for i in range(0, masks.shape[2], 128)
        ]
        masks = np.concatenate([x if x.ndim == 3 else x[:, :, None] for x in masks], axis=2)
    else:
        masks = cv2.resize(masks, (im0_shape[1], im0_shape[0]))

    if len(masks.shape) == 2:
        masks = masks[:, :, None]
    return masks

View on GitHub (pinned to 20d1d78a08)

Solutions

  1. Check the shape of the masks array right before scale_image is called; a segmentation inference should produce (num_masks, H, W) after processing_masks, e.g. print(masks.shape).
  2. If masks can be empty, guard upstream: skip scale_image when masks.size == 0 or masks.ndim < 2 instead of passing a squeezed empty array.
  3. Fix the producer: ensure the mask head / process_mask output keeps 2/3 dims (avoid np.squeeze without axis, avoid indexing that drops the spatial dims).
  4. If writing custom code, reshape to (H, W) or (H, W, 1) explicitly before calling: masks = masks.reshape(h, w, -1).

Example fix

# before
masks = scale_masks(masks, im0_shape)  # masks may be shape (0,) after squeeze
# after
if masks.ndim < 2 or masks.size == 0:
    masks = np.zeros((im0_shape[0], im0_shape[1], 0), dtype=np.float32)
else:
    masks = scale_masks(masks, im0_shape)
Defensive patterns

Strategy: type-guard

Validate before calling

import numpy as np

assert masks.ndim >= 2, (
    f"masks must be (H, W) or (H, W, N); got shape {masks.shape}. "
    "Check process_mask output and avoid squeezing empty mask stacks."
)
if masks.size == 0:
    masks = np.zeros((im0_shape[0], im0_shape[1], 0), dtype=np.float32)

Type guard

def is_rescalable_mask_array(masks) -> bool:
    """masks must be an ndarray with 2 or 3 dims and nonzero spatial size."""
    return isinstance(masks, np.ndarray) and masks.ndim in (2, 3) and masks.shape[0] > 0 and masks.shape[1] > 0

Try / catch

try:
    masks = scale_image(masks, im0_shape, ratio_pad=ratio_pad)
except ValueError as e:
    if 'should be 2 or 3' in str(e):
        LOGGER.warning(f"Skipping mask rescale for degenerate mask shape {masks.shape}")
        masks = np.zeros((im0_shape[0], im0_shape[1], 0), dtype=np.float32)
    else:
        raise

Prevention

When it happens

Trigger: Calling scale_image() (directly, or via segment/val.py or segment/predict.py post-processing) with masks that is a 0-d array or a 1-d array — e.g. an empty mask stack that was squeezed, a single mask stored as shape (N,) instead of (H, W), or a mis-shaped output from a custom mask head / prototyping code.

Common situations: Custom segmentation models whose mask output shape differs from YOLOv5's expected (N, H, W) or (H, W); running prediction on a batch that produced zero detections and downstream code squeezed the empty mask array; converting masks between tensor/numpy formats and losing a dimension; unit tests passing flat arrays.

Related errors


AI-assisted analysis of ultralytics/yolov5@20d1d78a08 (2026-08-15). Data as JSON: /api/errors/1181a7331c8e28ce. Report an issue: GitHub.