docling-project/docling · error · ValueError
prompt must be str or list[str], got {type(prompt)}
Error message
prompt must be str or list[str], got {type(prompt)} What it means
Strictest prompt typing of the VLM engines: the MLX raw-image path accepts only str (broadcast) or list (one per image). Passing a tuple, generator, dict, or None raises ValueError naming the received type — unlike sibling models, there is no implicit iteration over other sequences.
Source
Thrown at docling/models/vlm_pipeline_models/mlx_model.py:204
# 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:
# Grayscale array
from PIL import Image as PILImage
image = PILImage.fromarray(image.astype(np.uint8), mode="L")
else:View on GitHub (pinned to 61d76f1ff3)
Solutions
- Materialize sequences: prompt = list(prompt_tuple_or_gen) before the call
- Unwrap Optionals: prompt = prompt or DEFAULT_PROMPT
- Use a plain string for the shared-instruction case
Example fix
# before
model.process_images(images, (f"p{i}" for i in ids)) # generator -> ValueError
# after
model.process_images(images, [f"p{i}" for i in ids]) Defensive patterns
Strategy: type-guard
Validate before calling
if not isinstance(prompt, (str, list)):
prompt = list(prompt) if hasattr(prompt, '__iter__') else str(prompt)
assert isinstance(prompt, (str, list)) Type guard
from typing import Union
def narrow_mlx_prompt(p) -> Union[str, list[str]]:
if isinstance(p, (tuple, set)) or hasattr(p, '__next__'):
return list(p)
if not isinstance(p, (str, list)):
raise TypeError(f'prompt must be str or list[str], got {type(p)!r}')
return p Try / catch
try:
model.process_images(images, prompt)
except ValueError as e:
if 'prompt must be str or list' in str(e):
model.process_images(images, list(prompt) if not isinstance(prompt, str) else prompt)
else:
raise Prevention
- Materialize generators/tuples to list before any VLM call
- Handle Optional prompts with a default string early
- Write one prompt-normalization helper reused by every engine call
When it happens
Trigger: Passing a tuple or generator expression as prompt, or None from an unset Optional[str], to the MLX model's raw-image processing API.
Common situations: Passing a generator expression expecting lazy consumption; feeding a tuple from a loader API; forgetting to unwrap an Optional[str] that defaults to None.
Related errors
- Number of prompts ({len(prompt)}) must match number of image
- Supported input formats are PIL.Image.Image or numpy.ndarray
- Prompt list length ({len(prompt)}) must match image count ({
- Prompt list length ({len(prompt)}) must match image count ({
- Number of prompts ({len(prompt)}) must match number of image
AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14).
Data as JSON: /api/errors/2ccd4fba5cabd48a.
Report an issue: GitHub.