{"record":{"id":"77181e22e01e85b8","repo":"huggingface/transformers","slug":"invalid-image-shape-expected-either-expected-ndi","errorCode":null,"errorMessage":"Invalid image shape. Expected either {expected_ndims + 1} or {expected_ndims} dimensions, but got {images.ndim} dimensions.","messagePattern":"Invalid image shape\\. Expected either (.+?) or (.+?) dimensions, but got (.+?) dimensions\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/transformers/image_utils.py","lineNumber":192,"sourceCode":"            dimensions, an error is raised.\n    \"\"\"\n    if is_batched(images):\n        return images\n\n    # Either the input is a single image, in which case we create a list of length 1\n    if is_pil_image(images):\n        # PIL images are never batched\n        return [images]\n\n    if is_valid_image(images):\n        if images.ndim == expected_ndims + 1:\n            # Batch of images\n            images = list(images)\n        elif images.ndim == expected_ndims:\n            # Single image\n            images = [images]\n        else:\n            raise ValueError(\n                f\"Invalid image shape. Expected either {expected_ndims + 1} or {expected_ndims} dimensions, but got\"\n                f\" {images.ndim} dimensions.\"\n            )\n        return images\n    raise ValueError(\n        f\"Invalid image type. Expected either PIL.Image.Image, numpy.ndarray, or torch.Tensor, but got {type(images)}.\"\n    )\n\n\ndef make_flat_list_of_images(\n    images: list[ImageInput] | ImageInput,\n    expected_ndims: int = 3,\n) -> ImageInput:\n    \"\"\"\n    Ensure that the output is a flat list of images. If the input is a single image, it is converted to a list of length 1.\n    If the input is a nested list of images, it is converted to a flat list of images.\n    Args:\n        images (`Union[list[ImageInput], ImageInput]`):","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/huggingface/transformers/blob/a597f974857b3d92939971296bc0deb93d33d780/src/transformers/image_utils.py#L174-L210","documentation":"Raised by `transformers.image_utils.make_list_of_images` (default `expected_ndims=3`) when the input is a valid image type but its rank does not equal `expected_ndims` (single image) or `expected_ndims + 1` (batch). The helper's job is to normalize input into a Python list of images, so it must decide 'single vs batch'; an ambiguous rank makes that decision impossible. PIL images bypass this because they carry no batch dimension.","triggerScenarios":"Passing a 2D grayscale array (H, W) or 2D mask when expected_ndims=3; a 3D array where a 4D (batched) input was expected (expected_ndims=4 in some video/multi-frame processors); or a 5D tensor to a standard image path. Triggered via `processor.preprocess()` for processors that call this helper, or by calling it directly.","commonSituations":"Feeding grayscale/medical/multispectral data that lost its channel axis; squeezing a batch dimension too aggressively (`img.squeeze()` on (1, H, W, 1) gives (H, W)); or reusing a 3D shape where a video processor expects clips of shape (frames, C, H, W).","solutions":["Restore the channel axis: `img = img[..., None]` or `np.expand_dims(img, -1)` for a 2D grayscale array.","Match the rank to what the processor expects — keep 3 dims (C, H, W) for single images, 4 dims (N, C, H, W) for batches.","If the input is genuinely a batch, ensure it stayed 4D after loading/squeezing.","Convert to PIL first: PIL images are never ndim-checked."],"exampleFix":"// before\ngray = np.array(pil_gray_img)          # shape (H, W)\nimgs = make_list_of_images(gray)       # ValueError: got 2 dimensions\n\n// after\ngray = np.array(pil_gray_img)[..., None]  # (H, W, 1)\nimgs = make_list_of_images(gray)          # ok, treated as single image","handlingStrategy":"validation","validationCode":"def as_3d_image(img):\n    if hasattr(img, \"ndim\") and img.ndim == 2:  # grayscale lost its channel axis\n        img = img[..., None]\n    assert img.ndim in (3, 4), f\"expected 3 (single) or 4 (batch) dims, got {img.ndim}\"\n    return img","typeGuard":"def is_acceptable_image_rank(img, expected_ndims: int = 3) -> bool:\n    return img.ndim in (expected_ndims, expected_ndims + 1) if hasattr(img, \"ndim\") else True  # PIL passes","tryCatchPattern":null,"preventionTips":["Keep single images 3D (C, H, W) and batches 4D (N, C, H, W) throughout your pipeline.","Audit every squeeze() — prefer explicit squeeze(dim=...).","Add channel axes to 2D grayscale/mask arrays before preprocessing."],"tags":["image-processing","shape-validation","batching"],"backgroundTag":null,"analyzedSha":"a597f974857b3d92939971296bc0deb93d33d780","analyzedAt":"2026-08-14T18:24:08.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}