docling-project/docling · error · ValueError

Unsupported numpy array shape: {img.shape}

Error message

Unsupported numpy array shape: {img.shape}

What it means

ValueError from image normalization in TransformersExtractionModel: numpy arrays passed in image_batch must be 2-D grayscale (H x W) or 3-D with 3 or 4 channels; any other shape (e.g. (H, W, 1) or channels-first (C, H, W)) cannot be converted to a PIL image and is rejected.

Source

Thrown at docling/models/extraction/transformers_extraction_model.py:129

                    artifacts_path
                )

    def process_images(
        self,
        image_batch: Iterable[Union[Image, np.ndarray]],
        prompt: Union[str, list[str]],
    ) -> Iterable[VlmPrediction]:
        from PIL import Image as PILImage

        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

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

View on GitHub (pinned to 61d76f1ff3)

Solutions

  1. Normalize shapes upstream: img = img.reshape(img.shape[:2]) for (H, W, 1); img = img.transpose(1, 2, 0) for CHW.
  2. Pass PIL Images or a uniform list of RGB numpy arrays (H, W, 3) to avoid the ambiguity.
  3. Add an assert on shape before the call: img.ndim == 2 or (img.ndim == 3 and img.shape[2] in (3, 4)).

Example fix

# before
image_batch = [chw_array]  # shape (3, H, W) -> ValueError

# after
def to_hwc(img):
    return img.transpose(1, 2, 0) if img.ndim == 3 and img.shape[0] in (3, 4) else img
image_batch = [to_hwc(img) for img in image_batch]
Defensive patterns

Strategy: validation

Validate before calling

def to_pil_safe(img):
    if isinstance(img, np.ndarray):
        if img.ndim == 3 and img.shape[0] in (3, 4):
            img = img.transpose(1, 2, 0)      # CHW -> HWC
        if img.ndim == 3 and img.shape[2] == 1:
            img = img[:, :, 0]               # drop singleton channel
    return img
image_batch = [to_pil_safe(i) for i in image_batch]

Type guard

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

Try / catch

try:
    preds = model(image_batch, prompt)
except ValueError as e:
    if 'Unsupported numpy array shape' in str(e):
        image_batch = [to_pil_safe(i) for i in image_batch]
        preds = model(image_batch, prompt)

Prevention

When it happens

Trigger: Calling the extraction model with numpy image arrays whose ndim/shape[2] fall outside the accepted set; commonly grayscale arrays with a trailing singleton dimension or torch-style CHW arrays.

Common situations: Piping arrays from a preprocessing pipeline that normalizes to (H, W, 1); arrays converted from tensors with .numpy() keeping channels-first layout; mixed batches where some pages are (H, W) and others (H, W, 1).

Related errors


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