docling-project/docling · error · ValueError

Number of prompts ({len(prompt)}) must match number of image

Error message

Number of prompts ({len(prompt)}) must match number of images ({len(image_list)})

What it means

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.

Source

Thrown at docling/models/vlm_pipeline_models/mlx_model.py:199

                - list[str]: List of prompts (one per image, must match image count)

        Raises:
            ValueError: If prompt list length doesn't match image count.
        """
        # Convert image batch to list for length validation
        image_list = list(image_batch)

        if len(image_list) == 0:
            return

        # Handle prompt parameter
        if isinstance(prompt, str):
            # Single prompt for all images
            user_prompts = [prompt] * len(image_list)
        elif isinstance(prompt, list):
            # List of prompts (one per image)
            if len(prompt) != len(image_list):
                raise ValueError(
                    f"Number of prompts ({len(prompt)}) must match number of images ({len(image_list)})"
                )
            user_prompts = prompt
        else:
            raise ValueError(f"prompt must be str or list[str], got {type(prompt)}")

        # MLX models are not thread-safe - use global lock to serialize access
        with _MLX_GLOBAL_LOCK:
            _log.debug("MLX model: Acquired global lock for thread safety")
            for image, user_prompt in zip(image_list, user_prompts):
                # Convert numpy array to PIL Image if needed
                if isinstance(image, np.ndarray):
                    if image.ndim == 3 and image.shape[2] in [3, 4]:
                        # RGB or RGBA array
                        from PIL import Image as PILImage

                        image = PILImage.fromarray(image.astype(np.uint8))
                    elif image.ndim == 2:

View on GitHub (pinned to 61d76f1ff3)

Solutions

  1. Pass one shared prompt string when per-image text is not required
  2. Derive prompts from the same image list: user_prompts = [f(im) for im in image_list]
  3. 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)

Example fix

# before
out = model.process_images(images, all_prompts)  # len differs -> ValueError
# after
user_prompts = [all_prompts[m["page_no"]] for m in batch_meta]
assert len(user_prompts) == len(images)
out = model.process_images(images, user_prompts)
Defensive patterns

Strategy: validation

Validate before calling

image_list = list(image_batch)
if isinstance(prompt, list) and len(prompt) != len(image_list):
    prompt = [prompt[i % len(prompt)] for i in range(len(image_list))]  # or raise your own error

Type guard

def is_valid_mlx_prompt(prompt: object, n: int) -> bool:
    return isinstance(prompt, str) or (isinstance(prompt, list) and len(prompt) == n)

Try / catch

try:
    model.process_images(images, prompts)
except ValueError as e:
    if 'must match number of images' in str(e):
        model.process_images(images, shared_prompt_str)
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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