docling-project/docling · error · ValueError
Unsupported numpy array shape: {image.shape}
Error message
Unsupported numpy array shape: {image.shape} What it means
ApiVlmModel's numpy-to-PIL conversion only accepts 2-D grayscale arrays (H,W) and 3-D arrays whose last dimension is 3 (RGB) or 4 (RGBA). Any other layout — e.g. channels-first (3,H,W), single-column shape (H,W,1), or 4-D batch arrays — raises this ValueError before the image is sent to the API.
Source
Thrown at docling/models/vlm_pipeline_models/api_vlm_model.py:129
f"Prompt list length ({len(prompt)}) must match image count ({len(images)})"
)
prompts = prompt
def _process_single_image(image_prompt_pair):
image, prompt_text = image_prompt_pair
# Convert numpy array to PIL Image if needed
if isinstance(image, np.ndarray):
if image.ndim == 3 and image.shape[2] in [3, 4]:
from PIL import Image as PILImage
image = PILImage.fromarray(image.astype(np.uint8))
elif image.ndim == 2:
from PIL import Image as PILImage
image = PILImage.fromarray(image.astype(np.uint8), mode="L")
else:
raise ValueError(f"Unsupported numpy array shape: {image.shape}")
# Ensure image is in RGB mode
if image.mode != "RGB":
image = image.convert("RGB")
stop_reason = VlmStopReason.UNSPECIFIED
if self.vlm_options.custom_stopping_criteria:
# Instantiate any GenerationStopper classes before passing to streaming
instantiated_stoppers = []
for criteria in self.vlm_options.custom_stopping_criteria:
if isinstance(criteria, GenerationStopper):
instantiated_stoppers.append(criteria)
elif isinstance(criteria, type) and issubclass(
criteria, GenerationStopper
):
instantiated_stoppers.append(criteria())
# Skip non-GenerationStopper criteria (should have been caught in validation)View on GitHub (pinned to 61d76f1ff3)
Solutions
- Transpose channels-first arrays to HWC: arr.transpose(1,2,0)
- Squeeze (H,W,1) to (H,W), or use the 2-D grayscale path directly
- Pass docling Image objects or PIL Images instead of raw arrays to skip conversion entirely
Example fix
# before img = model_preprocessed_chw # shape (3, 1024, 768) out = model._process_batch([img], prompt) # after img = model_preprocessed_chw.transpose(1, 2, 0) # shape (1024, 768, 3) out = model._process_batch([img], prompt)
Defensive patterns
Strategy: type-guard
Validate before calling
import numpy as np
def is_supported_raster(a: np.ndarray) -> bool:
return a.ndim == 2 or (a.ndim == 3 and a.shape[2] in (3, 4))
for a in images:
if not is_supported_raster(a):
raise ValueError(f'bad shape {a.shape}') Type guard
import numpy as np
def to_hwc(a: np.ndarray) -> np.ndarray:
if a.ndim == 3 and a.shape[0] in (3, 4) and a.shape[2] not in (3, 4):
a = a.transpose(1, 2, 0)
if a.ndim == 3 and a.shape[2] == 1:
a = a[:, :, 0]
assert a.ndim == 2 or (a.ndim == 3 and a.shape[2] in (3, 4)), a.shape
return a Try / catch
try:
out = model._process_batch(images, prompt)
except ValueError as e:
if 'Unsupported numpy array shape' in str(e):
images = [to_hwc(im) for im in images]
out = model._process_batch(images, prompt)
else:
raise Prevention
- Standardize on HWC uint8 rasters at your pipeline boundary
- Convert torch tensors with .permute(1,2,0).cpu().numpy()
- Prefer passing docling Image objects so the library renders pages itself
When it happens
Trigger: Passing a channels-first array from a torch/opencv preprocessing step, an (H,W,1) array from an expanded grayscale mask, or a 4-D stacked batch where a single image is expected.
Common situations: Feeding model-preprocessed tensors (CHW convention) directly instead of raw page rasters; using np.expand_dims on grayscale images; accidentally passing a batch ndarray instead of iterating its items.
Related errors
- Unsupported numpy array shape: {img.shape}
- Unsupported numpy array shape: {image.shape}
- Unsupported numpy array shape: {image.shape}
- API runtime requires a URL
- Expected ApiVlmEngineOptions, got {type(options)}
AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14).
Data as JSON: /api/errors/a4613eb60cc7fd77.
Report an issue: GitHub.