{"record":{"id":"b91cd6e25baaeabd","repo":"docling-project/docling","slug":"unsupported-numpy-array-shape-img-shape-b91cd6","errorCode":null,"errorMessage":"Unsupported numpy array shape: {img.shape}","messagePattern":"Unsupported numpy array shape: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"docling/models/vlm_pipeline_models/vllm_model.py","lineNumber":287,"sourceCode":"    def process_images(\n        self,\n        image_batch: Iterable[Union[Image, np.ndarray]],\n        prompt: Union[str, list[str]],\n    ) -> Iterable[VlmPrediction]:\n        \"\"\"Process images in a single batched vLLM inference call.\"\"\"\n        import numpy as np\n        from PIL import Image as PILImage\n\n        # -- Normalize images to RGB PIL\n        pil_images: list[Image] = []\n        for img in image_batch:\n            if isinstance(img, np.ndarray):\n                if img.ndim == 3 and img.shape[2] in (3, 4):\n                    pil_img = PILImage.fromarray(img.astype(np.uint8))\n                elif img.ndim == 2:\n                    pil_img = PILImage.fromarray(img.astype(np.uint8), mode=\"L\")\n                else:\n                    raise ValueError(f\"Unsupported numpy array shape: {img.shape}\")\n            else:\n                pil_img = img\n            if pil_img.mode != \"RGB\":\n                pil_img = pil_img.convert(\"RGB\")\n            pil_images.append(pil_img)\n\n        if not pil_images:\n            return\n\n        # Normalize prompts\n        if isinstance(prompt, str):\n            user_prompts = [prompt] * len(pil_images)\n        elif isinstance(prompt, list):\n            if len(prompt) != len(pil_images):\n                raise ValueError(\n                    f\"Number of prompts ({len(prompt)}) must match number of images ({len(pil_images)})\"\n                )\n            user_prompts = prompt","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/docling-project/docling/blob/61d76f1ff3f8428065465889f7b4577da7df704c/docling/models/vlm_pipeline_models/vllm_model.py#L269-L305","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["Reshape/ squeeze to HxW, HxWx3, or HxWx4 before passing: arr = arr.squeeze() for (H,W,1), arr = arr.transpose(1,2,0) for CHW","Split batched arrays (N,H,W,C) into individual HxWxC arrays and pass them as separate batch items","Convert to PIL.Image beforehand (PIL images are accepted as-is and normalized to RGB downstream)"],"exampleFix":"# before\nimg = gray[:,:,None]          # shape (H, W, 1) -> ValueError\nmodel.generate([img], prompt)\n\n# after\nimg = gray                    # shape (H, W)\nmodel.generate([img], prompt)","handlingStrategy":"type-guard","validationCode":"import numpy as np\n\ndef is_supported_ndarray(img: np.ndarray) -> bool:\n    return img.ndim == 2 or (img.ndim == 3 and img.shape[2] in (3, 4))","typeGuard":"from typing import Any\nimport numpy as np\n\ndef is_vllm_image(x: Any) -> bool:\n    return hasattr(x, 'mode') or (isinstance(x, np.ndarray) and (x.ndim == 2 or (x.ndim == 3 and x.shape[2] in (3, 4))))","tryCatchPattern":null,"preventionTips":["Standardize images to RGB PIL or HxWx3 uint8 numpy at your pipeline boundary","squeeze() singleton channel dims and transpose CHW->HWC right after any torchvision/preprocessing step","Pass batches as lists of single images, never as one stacked N-dimensional array"],"tags":["vlm","vllm","numpy","image-processing"],"backgroundTag":null,"analyzedSha":"61d76f1ff3f8428065465889f7b4577da7df704c","analyzedAt":"2026-08-14T23:53:18.727Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}