huggingface/transformers · error · TypeError

Input image must be of type np.ndarray, got {type(image)}

Error message

Input image must be of type np.ndarray, got {type(image)}

What it means

to_channel_dimension_format is a numpy-only transform: it raises TypeError immediately when `image` is not an np.ndarray. Torch tensors, PIL images, and lists are not handled here; callers must convert first. The check exists because the transpose logic below assumes ndarray semantics.

Source

Thrown at src/transformers/image_transforms.py:68

) -> np.ndarray:
    """
    Converts `image` to the channel dimension format specified by `channel_dim`. The input
    can have arbitrary number of leading dimensions. Only last three dimension will be permuted
    to format the `image`.

    Args:
        image (`numpy.ndarray`):
            The image to have its channel dimension set.
        channel_dim (`ChannelDimension`):
            The channel dimension format to use.
        input_channel_dim (`ChannelDimension`, *optional*):
            The channel dimension format of the input image. If not provided, it will be inferred from the input image.

    Returns:
        `np.ndarray`: The image with the channel dimension set to `channel_dim`.
    """
    if not isinstance(image, np.ndarray):
        raise TypeError(f"Input image must be of type np.ndarray, got {type(image)}")

    if input_channel_dim is None:
        input_channel_dim = infer_channel_dimension_format(image)

    target_channel_dim = ChannelDimension(channel_dim)
    if input_channel_dim == target_channel_dim:
        return image

    if target_channel_dim == ChannelDimension.FIRST:
        axes = list(range(image.ndim - 3)) + [image.ndim - 1, image.ndim - 3, image.ndim - 2]
        image = image.transpose(axes)
    elif target_channel_dim == ChannelDimension.LAST:
        axes = list(range(image.ndim - 3)) + [image.ndim - 2, image.ndim - 1, image.ndim - 3]
        image = image.transpose(axes)
    else:
        raise ValueError(f"Unsupported channel dimension format: {channel_dim}")

    return image

View on GitHub (pinned to a597f97485)

Solutions

  1. Convert before calling: image = tensor.detach().cpu().numpy() for torch tensors.
  2. For PIL images, use np.array(image) first.
  3. Audit the preprocessing pipeline to keep a single representation (numpy) until tensors are needed by the model.
  4. Check for accidental list inputs (e.g. [img] wrapping) and index out the ndarray.

Example fix

# before
img = to_channel_dimension_format(batch_tensor, ChannelDimension.LAST)  # TypeError

# after
img_np = batch_tensor.detach().cpu().numpy()
img = to_channel_dimension_format(img_np, ChannelDimension.LAST)
Defensive patterns

Strategy: type-guard

Validate before calling

import numpy as np
assert isinstance(image, np.ndarray), f"expected np.ndarray, got {type(image)}"

Type guard

def ensure_numpy(image):
    if isinstance(image, np.ndarray):
        return image
    if hasattr(image, "numpy"):  # torch tensor
        return image.detach().cpu().numpy()
    if hasattr(image, "__array__"):  # PIL and friends
        return np.asarray(image)
    raise TypeError(f"cannot convert {type(image)} to np.ndarray")

Prevention

When it happens

Trigger: Calling to_channel_dimension_format(torch_tensor, ChannelDimension.LAST) or passing a PIL.Image.Image; commonly hit indirectly from rescale/normalize/center_crop pipelines when a tensor leaks in from a mixed torch/numpy preprocessing loop.

Common situations: Batch pipelines that alternate between torch and numpy, passing model-batch tensors into functions designed for single numpy images, or forgetting .numpy() / .detach().cpu().numpy() after GPU inference feeding pre-processing.

Related errors


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