{"record":{"id":"7397649ec7894153","repo":"docling-project/docling","slug":"prompt-must-be-str-or-list-str-got-type-prompt-739764","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/vllm_model.py","lineNumber":307,"sourceCode":"                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\n        else:\n            raise ValueError(f\"prompt must be str or list[str], got {type(prompt)}\")\n\n        # Format prompts\n        prompts: list[str] = [self.formulate_prompt(up) for up in user_prompts]\n\n        # Build vLLM inputs\n        llm_inputs = [\n            {\"prompt\": p, \"multi_modal_data\": {\"image\": im}}\n            for p, im in zip(prompts, pil_images)\n        ]\n\n        # Generate\n        assert self.llm is not None and self.sampling_params is not None\n        start_time = time.time()\n        outputs = self.llm.generate(llm_inputs, sampling_params=self.sampling_params)  # type: ignore\n        generation_time = time.time() - start_time\n\n        # Optional debug\n        if outputs:","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/docling-project/docling/blob/61d76f1ff3f8428065465889f7b4577da7df704c/docling/models/vlm_pipeline_models/vllm_model.py#L289-L325","documentation":"The prompt parameter of the vLLM VLM generation API accepts only str (broadcast to all images) or list (one prompt per image). Any other type — int, dict, tuple, a generator, an ndarray — fails this isinstance check and raises ValueError with the offending type. This is the API's input contract enforcement before any formatting happens.","triggerScenarios":"Calling generate(images, prompt=0), prompt=('describe',), prompt=iter([...]), prompt={'role': 'user', ...} (chat-format dict), or a numpy array of strings — anything that is neither str nor list.","commonSituations":"Porting code from another SDK that accepts OpenAI-style message dicts or tuples; passing a generator expression; config-driven prompt values parsed from YAML as a non-string scalar (e.g. `prompt: 1`).","solutions":["Pass a plain Python str for a shared prompt, or list[str] matched to the image count","Convert chat-style messages to a single string first: prompt = '\\n'.join(m['content'] for m in messages)","Materialize generators: prompt = list(prompt_gen)"],"exampleFix":"# before\nmodel.generate(images, prompt={'role': 'user', 'content': 'describe'})\n\n# after\nmodel.generate(images, prompt='describe')","handlingStrategy":"type-guard","validationCode":"if not isinstance(prompt, (str, list)) or (isinstance(prompt, list) and not all(isinstance(p, str) for p in prompt)):\n    raise TypeError(f'prompt must be str or list[str], got {type(prompt).__name__}')","typeGuard":"def is_valid_prompt(p) -> bool:\n    return isinstance(p, str) or (isinstance(p, list) and all(isinstance(x, str) for x in p))","tryCatchPattern":null,"preventionTips":["Normalize prompts at config-load time: coerce scalars to str and materialize iterables to list","Keep the API contract (str | list[str]) in the type hints of your own wrapper"],"tags":["vlm","vllm","prompt","type-error"],"backgroundTag":null,"analyzedSha":"61d76f1ff3f8428065465889f7b4577da7df704c","analyzedAt":"2026-08-14T23:53:18.727Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}