{"record":{"id":"503f1f47cacb7279","repo":"run-llama/llama_index","slug":"llm-only-supports-text-inputs","errorCode":null,"errorMessage":"LLM only supports text inputs","messagePattern":"LLM only supports text inputs","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"llama-index-core/llama_index/core/base/llms/base.py","lineNumber":80,"sourceCode":"        Emitted via instrumentation events and callback payloads, so it must\n        never contain credentials (e.g. ``api_key``) or auth headers. Defaults\n        to the model's metadata; subclasses may override to add safe details.\n        \"\"\"\n        return {\"class_name\": self.class_name(), **self.metadata.model_dump()}\n\n    def convert_chat_messages(self, messages: Sequence[ChatMessage]) -> List[Any]:\n        \"\"\"Convert chat messages to an LLM specific message format.\"\"\"\n        converted_messages = []\n        for message in messages:\n            if isinstance(message.content, str):\n                converted_messages.append(message)\n            elif isinstance(message.content, List):\n                content_string = \"\"\n                for block in message.content:\n                    if isinstance(block, TextBlock):\n                        content_string += block.text\n                    else:\n                        raise ValueError(\"LLM only supports text inputs\")\n                message.content = content_string\n                converted_messages.append(message)\n            else:\n                raise ValueError(f\"Invalid message content: {message.content!s}\")\n\n        return converted_messages\n\n    @abstractmethod\n    def chat(self, messages: Sequence[ChatMessage], **kwargs: Any) -> ChatResponse:\n        \"\"\"\n        Chat endpoint for LLM.\n\n        Args:\n            messages (Sequence[ChatMessage]):\n                Sequence of chat messages.\n            kwargs (Any):\n                Additional keyword arguments to pass to the LLM.\n","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/run-llama/llama_index/blob/afd0fef371831f9bda13e5af7167cf4e981278ab/llama-index-core/llama_index/core/base/llms/base.py#L62-L98","documentation":"Raised by BaseLLM.convert_chat_messages when a ChatMessage's content is a list of blocks and at least one block is not a TextBlock. This base implementation flattens list content into a plain string for LLMs that only accept text, so ImageBlock/AudioBlock/etc. in the list are unsupported.","triggerScenarios":"Calling llm.chat(messages=[ChatMessage(blocks=[TextBlock(...), ImageBlock(...)])]) on an LLM class that uses the base convert_chat_messages (text-only LLMs, e.g. some local/open-source implementations) instead of a multimodal one.","commonSituations":"Sending multimodal messages to a text-only model; reusing a multimodal prompt with a non-multimodal LLM after swapping Settings.llm; older code where content strings became block lists after the multi-block ChatMessage refactor.","solutions":["Use a multimodal LLM class that overrides convert_chat_messages (e.g. OpenAI/AzureOpenAI multimodal LLMs) when you need image/audio blocks.","Strip non-text blocks before calling a text-only LLM: keep only TextBlock entries and join their .text.","Pass content as a plain string for text-only models: ChatMessage.from_str(...) or content=\"...\"."],"exampleFix":"# before\nmsgs = [ChatMessage(blocks=[TextBlock(text=\"describe\"), ImageBlock(image=bytes(...))], role=MessageRole.USER)]\nresp = text_only_llm.chat(msgs)\n\n# after\nmsgs = [ChatMessage(content=\"describe\", role=MessageRole.USER)]\nresp = text_only_llm.chat(msgs)\n# or switch to a multimodal LLM: Settings.llm = OpenAI(model=\"gpt-4o\")","handlingStrategy":"validation","validationCode":"from llama_index.core.base.llms.types import TextBlock\ntexts = [b.text for b in msg.blocks if isinstance(b, TextBlock)]\nsafe_msg = ChatMessage(content=\"\\n\".join(texts), role=msg.role)","typeGuard":"def is_text_only(msg: ChatMessage) -> bool:\n    return isinstance(msg.content, str) or all(\n        hasattr(b, \"text\") for b in (msg.blocks or [])\n    )","tryCatchPattern":"try:\n    resp = llm.chat(msgs)\nexcept ValueError as e:\n    if \"text inputs\" in str(e):\n        msgs = [strip_to_text(m) for m in msgs]\n        resp = llm.chat(msgs)","preventionTips":["Check model capability (multimodal or not) before building block lists.","Keep one prompt path per modality rather than reusing multimodal messages everywhere."],"tags":["llama-index","llm","multimodal","chat-message"],"backgroundTag":null,"analyzedSha":"afd0fef371831f9bda13e5af7167cf4e981278ab","analyzedAt":"2026-08-15T05:42:58.429Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}