{"record":{"id":"f525030dd02b9e73","repo":"docling-project/docling","slug":"number-of-prompts-len-prompt-must-match-numbe-f52503","errorCode":null,"errorMessage":"Number of prompts ({len(prompt)}) must match number of images ({len(image_list)})","messagePattern":"Number of prompts \\((.+?)\\) must match number of images \\((.+?)\\)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"docling/models/vlm_pipeline_models/mlx_model.py","lineNumber":199,"sourceCode":"                - list[str]: List of prompts (one per image, must match image count)\n\n        Raises:\n            ValueError: If prompt list length doesn't match image count.\n        \"\"\"\n        # Convert image batch to list for length validation\n        image_list = list(image_batch)\n\n        if len(image_list) == 0:\n            return\n\n        # Handle prompt parameter\n        if isinstance(prompt, str):\n            # Single prompt for all images\n            user_prompts = [prompt] * len(image_list)\n        elif isinstance(prompt, list):\n            # List of prompts (one per image)\n            if len(prompt) != len(image_list):\n                raise ValueError(\n                    f\"Number of prompts ({len(prompt)}) must match number of images ({len(image_list)})\"\n                )\n            user_prompts = prompt\n        else:\n            raise ValueError(f\"prompt must be str or list[str], got {type(prompt)}\")\n\n        # MLX models are not thread-safe - use global lock to serialize access\n        with _MLX_GLOBAL_LOCK:\n            _log.debug(\"MLX model: Acquired global lock for thread safety\")\n            for image, user_prompt in zip(image_list, user_prompts):\n                # Convert numpy array to PIL Image if needed\n                if isinstance(image, np.ndarray):\n                    if image.ndim == 3 and image.shape[2] in [3, 4]:\n                        # RGB or RGBA array\n                        from PIL import Image as PILImage\n\n                        image = PILImage.fromarray(image.astype(np.uint8))\n                    elif image.ndim == 2:","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/docling-project/docling/blob/61d76f1ff3f8428065465889f7b4577da7df704c/docling/models/vlm_pipeline_models/mlx_model.py#L181-L217","documentation":"The MLX model's raw-image path mirrors the other engines: a string prompt is broadcast to all images, a list must have exactly one prompt per image. This ValueError is the length-mismatch case for the list branch.","triggerScenarios":"Calling the MLX raw-image processing API with a list of prompts whose length differs from image_list, e.g. prompts built from all pages of a document while processing only a subset of pages as images.","commonSituations":"Building prompts from full documents while processing page subsets; async producers generating prompts at a different rate than images are consumed; reusing batching code from another engine with different chunk sizes.","solutions":["Pass one shared prompt string when per-image text is not required","Derive prompts from the same image list: user_prompts = [f(im) for im in image_list]","Guard with a length equality check before invoking the MLX model (it serializes on a global lock, so failing early also saves the lock acquisition)"],"exampleFix":"# before\nout = model.process_images(images, all_prompts)  # len differs -> ValueError\n# after\nuser_prompts = [all_prompts[m[\"page_no\"]] for m in batch_meta]\nassert len(user_prompts) == len(images)\nout = model.process_images(images, user_prompts)","handlingStrategy":"validation","validationCode":"image_list = list(image_batch)\nif isinstance(prompt, list) and len(prompt) != len(image_list):\n    prompt = [prompt[i % len(prompt)] for i in range(len(image_list))]  # or raise your own error","typeGuard":"def is_valid_mlx_prompt(prompt: object, n: int) -> bool:\n    return isinstance(prompt, str) or (isinstance(prompt, list) and len(prompt) == n)","tryCatchPattern":"try:\n    model.process_images(images, prompts)\nexcept ValueError as e:\n    if 'must match number of images' in str(e):\n        model.process_images(images, shared_prompt_str)\n    else:\n        raise","preventionTips":["Zip images and prompts into pairs before the MLX call","Remember MLX serializes on a global lock — validate before entering to save latency","Recompute prompt lists whenever the image list is filtered"],"tags":["mlx","prompt","batching","validation"],"backgroundTag":null,"analyzedSha":"61d76f1ff3f8428065465889f7b4577da7df704c","analyzedAt":"2026-08-14T23:53:18.727Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}