{"record":{"id":"cc2d0c23ed3491d1","repo":"BerriAI/litellm","slug":"prompt-must-be-a-non-empty-string-or-a-non-empty","errorCode":null,"errorMessage":"`prompt` must be a non-empty string or a non-empty list of strings. Got: {prompt_type_name}.","messagePattern":"`prompt` must be a non-empty string or a non-empty list of strings\\. Got: (.+?)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/litellm_core_utils/prompt_templates/common_utils.py","lineNumber":1878,"sourceCode":"def text_completion_prompt_to_messages(prompt: object) -> tuple[AllMessageValues, ...]:\n    \"\"\"\n    Wrap an OpenAI ``/v1/completions`` ``prompt`` into Chat Completion messages.\n\n    Mirrors what ``litellm.text_completion`` does on the real-time path: a\n    string becomes a single user message, and a list of strings becomes one\n    user message per element. Pre-tokenized prompts (``list[int]`` /\n    ``list[list[int]]``) are only meaningful for the OpenAI-family text\n    endpoints, so they are rejected here rather than silently forwarded, as is\n    an empty prompt, which every chat-shaped provider rejects downstream.\n    \"\"\"\n    prompt_type_name: Final = type(prompt).__name__\n    if isinstance(prompt, str) and prompt:\n        return (ChatCompletionUserMessage(role=\"user\", content=prompt),)\n    entries: Final = cast(\"Sequence[object]\", prompt) if isinstance(prompt, Sequence) else ()\n    string_entries: Final = tuple(entry for entry in entries if isinstance(entry, str) and entry)\n    if string_entries and len(string_entries) == len(entries):\n        return tuple(ChatCompletionUserMessage(role=\"user\", content=entry) for entry in string_entries)\n    raise ValueError(f\"`prompt` must be a non-empty string or a non-empty list of strings. Got: {prompt_type_name}.\")\n","sourceCodeStart":1860,"sourceCodeEnd":1879,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/litellm_core_utils/prompt_templates/common_utils.py#L1860-L1879","documentation":"This ValueError comes from LiteLLM's chat-endpoint input normalization: when you pass a bare `prompt` (instead of `messages`) it must be a non-empty string or a non-empty list of non-empty strings. Pre-tokenized prompts (list[int]/list[list[int]]) are deliberately rejected because only OpenAI-family text endpoints accept them. Anything else (None, empty string, empty list, mixed types, ints) fails fast here.","triggerScenarios":"Calling a chat-shaped completion (e.g. litellm.completion or a provider chat handler) with prompt=\"\", prompt=[], prompt=[\"hi\", \"\"], prompt=None, or prompt=[1,2,3] instead of using the messages= parameter with proper role objects.","commonSituations":"Porting code from OpenAI's legacy completions API (prompt=...) to a chat model; dynamic prompts that are empty after template substitution or stripping; accidentally passing token IDs from a tokenizer to a chat endpoint.","solutions":["Pass a non-empty prompt: validate/strip the string and supply a default (e.g. '.') when it is empty","Use the messages=[{\"role\": \"user\", \"content\": ...}] API instead of prompt= for chat models","For token-ID prompts, use an OpenAI-family text completion endpoint, not the chat path"],"exampleFix":"# before\nresp = litellm.completion(model=\"gpt-4o-mini\", prompt=user_text)  # user_text may be \"\"\n\n# after\nuser_text = user_text.strip() or \".\"\nresp = litellm.completion(model=\"gpt-4o-mini\", messages=[{\"role\": \"user\", \"content\": user_text}])","handlingStrategy":"validation","validationCode":"def normalize_prompt(prompt):\n    if isinstance(prompt, str) and prompt.strip():\n        return [{\"role\": \"user\", \"content\": prompt}]\n    if isinstance(prompt, list) and prompt and all(isinstance(p, str) and p.strip() for p in prompt):\n        return [{\"role\": \"user\", \"content\": p} for p in prompt]\n    raise ValueError(\"prompt must be a non-empty string or non-empty list of non-empty strings\")\n\nmessages = normalize_prompt(user_input)","typeGuard":"from typing import Any\n\ndef is_valid_prompt(p: Any) -> bool:\n    if isinstance(p, str):\n        return bool(p.strip())\n    if isinstance(p, list):\n        return bool(p) and all(isinstance(x, str) and x.strip() for x in p)\n    return False","tryCatchPattern":null,"preventionTips":["Prefer the messages=[...] API over prompt= for chat models","Strip and default-empty user input before building requests","Never pass token IDs (list[int]) to chat-shaped endpoints"],"tags":["validation","prompt","chat-api","input"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}