huggingface/transformers · error · ValueError

mean must have {num_channels} elements if it is an iterable,

Error message

mean must have {num_channels} elements if it is an iterable, got {len(mean)}

What it means

When mean is a Collection, normalize broadcasts it per channel, so its length must equal the image's channel count (inferred from the channel axis); otherwise ValueError. Scalars are fine and get replicated, only mismatched iterables fail.

Source

Thrown at src/transformers/image_transforms.py:424

            The channel dimension format of the input image. If unset, will use the inferred format from the input.
    """
    if not isinstance(image, np.ndarray):
        raise TypeError("image must be a numpy array")

    if input_data_format is None:
        input_data_format = infer_channel_dimension_format(image)

    channel_axis = get_channel_dimension_axis(image, input_data_format=input_data_format)
    num_channels = image.shape[channel_axis]

    # We cast to float32 to avoid errors that can occur when subtracting uint8 values.
    # We preserve the original dtype if it is a float type to prevent upcasting float16.
    if not np.issubdtype(image.dtype, np.floating):
        image = image.astype(np.float32)

    if isinstance(mean, Collection):
        if len(mean) != num_channels:
            raise ValueError(f"mean must have {num_channels} elements if it is an iterable, got {len(mean)}")
    else:
        mean = [mean] * num_channels
    mean = np.array(mean, dtype=image.dtype)

    if isinstance(std, Collection):
        if len(std) != num_channels:
            raise ValueError(f"std must have {num_channels} elements if it is an iterable, got {len(std)}")
    else:
        std = [std] * num_channels
    std = np.array(std, dtype=image.dtype)

    if input_data_format == ChannelDimension.LAST:
        image = (image - mean) / std
    else:
        image = ((image.T - mean) / std).T

    image = to_channel_dimension_format(image, data_format, input_data_format) if data_format is not None else image
    return image

View on GitHub (pinned to a597f97485)

Solutions

  1. Match lengths: 3-element mean/std for RGB, 1-element for grayscale.
  2. Pass scalars to apply one value to all channels: mean=0.5.
  3. Compute channel count first and build stats accordingly (len(img.shape[channel_axis])).

Example fix

# before
img = normalize(gray_img, mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])  # 1-channel image

# after
img = normalize(gray_img, mean=0.5, std=0.5)
Defensive patterns

Strategy: validation

Validate before calling

from transformers.image_utils import get_channel_dimension_axis
n = image.shape[get_channel_dimension_axis(image, input_data_format=input_data_format)]
if isinstance(mean, (list, tuple)):
    assert len(mean) == n, f"mean needs {n} elements, got {len(mean)}"
if isinstance(std, (list, tuple)):
    assert len(std) == n, f"std needs {n} elements, got {len(std)}"

Type guard

def stats_match_channels(mean, std, n) -> bool:
    ok = lambda v: not isinstance(v, (list, tuple)) or len(v) == n
    return ok(mean) and ok(std)

Prevention

When it happens

Trigger: normalize(rgb_image, mean=[0.5], std=0.5) with a 3-channel image; grayscale image with 3-element mean; mean lists of length 2 for 3 channels.

Common situations: Hardcoding RGB stats but running grayscale/RGBA images, using dataset-specific channel counts (e.g. satellite imagery with >3 bands), or typo'd stat lists.

Related errors


AI-assisted analysis of huggingface/transformers@a597f97485 (2026-08-14). Data as JSON: /api/errors/2dbbf35cfe77deb4. Report an issue: GitHub.