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 NuExtractTransformersModel: a numpy image in the batch must be 2-D grayscale (H x W) or 3-D with 3 or 4 channels (H x W x 3/4). Any other shape (e.g. H x W x 1, or higher-dimensional arrays) is rejected because PIL cannot interpret it as an image.

Source

Thrown at docling/models/extraction/nuextract_transformers_model.py:194

        Args:
            image_batch: Iterable of PIL Images or numpy arrays
            prompt: Either:
                - str: Single template used for all images
                - list[str]: List of templates (one per image, must match image count)
        """
        import torch
        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 templates (1 per image)
        if isinstance(prompt, str):
            templates = [prompt] * len(pil_images)
        else:
            if len(prompt) != len(pil_images):
                raise ValueError(
                    f"Number of templates ({len(prompt)}) must match number of images ({len(pil_images)})"
                )
            templates = prompt

View on GitHub (pinned to 61d76f1ff3)

Solutions

  1. Squeeze singleton channels: img = img.squeeze(-1) for (H, W, 1) arrays so they become 2-D.
  2. Convert channels-first arrays: img = img.transpose(1, 2, 0) before passing.
  3. Pass PIL Images directly instead of numpy arrays to sidestep shape interpretation.

Example fix

# before
image_batch = [gray_hwc1_array]  # shape (H, W, 1) -> ValueError

# after
image_batch = [img.squeeze(-1) if img.ndim == 3 and img.shape[2] == 1 else img
                for img in image_batch]
# or pass PIL images: image_batch = [Image.fromarray(arr)]
Defensive patterns

Strategy: validation

Validate before calling

def valid_image_shape(img: 'np.ndarray') -> bool:
    return img.ndim == 2 or (img.ndim == 3 and img.shape[2] in (3, 4))
assert all(valid_image_shape(i) for i in image_batch if isinstance(i, np.ndarray))

Type guard

def is_hwc_array(img) -> bool:
    return isinstance(img, np.ndarray) and (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 = [np.squeeze(i) if isinstance(i, np.ndarray) and i.ndim == 3 and i.shape[2] == 1 else i for i in image_batch]
        preds = model(image_batch, prompt)

Prevention

When it happens

Trigger: Passing image_batch entries as numpy arrays with img.ndim not in {2} and not (ndim==3 and shape[2] in (3,4)); typical offenders are (H, W, 1) arrays from grayscale pipelines or float arrays with unexpected trailing dimensions.

Common situations: Feeding model-preprocessed tensors or grayscale arrays saved with a singleton channel dimension; images coming from a different preprocessing stage that kept channels-first (C, H, W) layout.

Related errors


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