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
- 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).
- 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.
- 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).
- 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
- Never call np.squeeze on mask stacks without an explicit axis; empty detection batches collapse to <2 dims.
- Keep mask tensors in (N, H, W) until the final per-image step.
- In custom mask heads, assert the output is 3D before handing it to postprocessing.
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.