docling-project/docling · error · ValueError

Unsupported numpy array shape: {img.shape}

Error message

Unsupported numpy array shape: {img.shape}

What it means

Raised while normalizing an image batch for vLLM generation: each numpy array must be either 2-D (grayscale, converted with mode 'L') or 3-D with last dimension 3 or 4 (RGB/RGBA). Any other rank or channel count (e.g. shape (H,W,1), (H,W,2), or 4-D batch arrays) raises ValueError. It guards PIL.Image.fromarray which would otherwise fail cryptically or silently misinterpret the buffer.

Source

Thrown at docling/models/vlm_pipeline_models/vllm_model.py:287

    def process_images(
        self,
        image_batch: Iterable[Union[Image, np.ndarray]],
        prompt: Union[str, list[str]],
    ) -> Iterable[VlmPrediction]:
        """Process images in a single batched vLLM inference call."""
        import numpy as np
        from PIL import Image as PILImage

        # -- Normalize images to RGB PIL
        pil_images: list[Image] = []
        for img in image_batch:
            if isinstance(img, np.ndarray):
                if img.ndim == 3 and img.shape[2] in (3, 4):
                    pil_img = PILImage.fromarray(img.astype(np.uint8))
                elif img.ndim == 2:
                    pil_img = PILImage.fromarray(img.astype(np.uint8), mode="L")
                else:
                    raise ValueError(f"Unsupported numpy array shape: {img.shape}")
            else:
                pil_img = img
            if pil_img.mode != "RGB":
                pil_img = pil_img.convert("RGB")
            pil_images.append(pil_img)

        if not pil_images:
            return

        # Normalize prompts
        if isinstance(prompt, str):
            user_prompts = [prompt] * len(pil_images)
        elif isinstance(prompt, list):
            if len(prompt) != len(pil_images):
                raise ValueError(
                    f"Number of prompts ({len(prompt)}) must match number of images ({len(pil_images)})"
                )
            user_prompts = prompt

View on GitHub (pinned to 61d76f1ff3)

Solutions

  1. Reshape/ squeeze to HxW, HxWx3, or HxWx4 before passing: arr = arr.squeeze() for (H,W,1), arr = arr.transpose(1,2,0) for CHW
  2. Split batched arrays (N,H,W,C) into individual HxWxC arrays and pass them as separate batch items
  3. Convert to PIL.Image beforehand (PIL images are accepted as-is and normalized to RGB downstream)

Example fix

# before
img = gray[:,:,None]          # shape (H, W, 1) -> ValueError
model.generate([img], prompt)

# after
img = gray                    # shape (H, W)
model.generate([img], prompt)
Defensive patterns

Strategy: type-guard

Validate before calling

import numpy as np

def is_supported_ndarray(img: np.ndarray) -> bool:
    return img.ndim == 2 or (img.ndim == 3 and img.shape[2] in (3, 4))

Type guard

from typing import Any
import numpy as np

def is_vllm_image(x: Any) -> bool:
    return hasattr(x, 'mode') or (isinstance(x, np.ndarray) and (x.ndim == 2 or (x.ndim == 3 and x.shape[2] in (3, 4))))

Prevention

When it happens

Trigger: Calling the vLLM model's generate/interaction API with numpy images that are not HxW, HxWx3, or HxWx4 — e.g. passing a (N,H,W,3) batch as one array, a float array with an alpha-only channel, or an array with a singleton channel dimension kept via np.newaxis.

Common situations: Feeding preprocessed tensors from another pipeline (CHW instead of HWC), keeping channel dim with keepdims=True from np.min/np.max, grayscale stored as (H,W,1), or float arrays that pass the ndim check but need astype(uint8).

Related errors


AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14). Data as JSON: /api/errors/b91cd6e25baaeabd. Report an issue: GitHub.