{"record":{"id":"2ccd4fba5cabd48a","repo":"docling-project/docling","slug":"prompt-must-be-str-or-list-str-got-type-prompt","errorCode":null,"errorMessage":"prompt must be str or list[str], got {type(prompt)}","messagePattern":"prompt must be str or list\\[str\\], got (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"docling/models/vlm_pipeline_models/mlx_model.py","lineNumber":204,"sourceCode":"        # 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:\n                        # Grayscale array\n                        from PIL import Image as PILImage\n\n                        image = PILImage.fromarray(image.astype(np.uint8), mode=\"L\")\n                    else:","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/docling-project/docling/blob/61d76f1ff3f8428065465889f7b4577da7df704c/docling/models/vlm_pipeline_models/mlx_model.py#L186-L222","documentation":"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.","triggerScenarios":"Passing a tuple or generator expression as prompt, or None from an unset Optional[str], to the MLX model's raw-image processing API.","commonSituations":"Passing a generator expression expecting lazy consumption; feeding a tuple from a loader API; forgetting to unwrap an Optional[str] that defaults to None.","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"],"exampleFix":"# before\nmodel.process_images(images, (f\"p{i}\" for i in ids))  # generator -> ValueError\n# after\nmodel.process_images(images, [f\"p{i}\" for i in ids])","handlingStrategy":"type-guard","validationCode":"if not isinstance(prompt, (str, list)):\n    prompt = list(prompt) if hasattr(prompt, '__iter__') else str(prompt)\nassert isinstance(prompt, (str, list))","typeGuard":"from typing import Union\n\ndef narrow_mlx_prompt(p) -> Union[str, list[str]]:\n    if isinstance(p, (tuple, set)) or hasattr(p, '__next__'):\n        return list(p)\n    if not isinstance(p, (str, list)):\n        raise TypeError(f'prompt must be str or list[str], got {type(p)!r}')\n    return p","tryCatchPattern":"try:\n    model.process_images(images, prompt)\nexcept ValueError as e:\n    if 'prompt must be str or list' in str(e):\n        model.process_images(images, list(prompt) if not isinstance(prompt, str) else prompt)\n    else:\n        raise","preventionTips":["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"],"tags":["mlx","prompt","type-error","validation"],"backgroundTag":null,"analyzedSha":"61d76f1ff3f8428065465889f7b4577da7df704c","analyzedAt":"2026-08-14T23:53:18.727Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}