run-llama/llama_index · error · ValueError
LLM only supports text inputs
Error message
LLM only supports text inputs
What it means
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.
Source
Thrown at llama-index-core/llama_index/core/base/llms/base.py:80
Emitted via instrumentation events and callback payloads, so it must
never contain credentials (e.g. ``api_key``) or auth headers. Defaults
to the model's metadata; subclasses may override to add safe details.
"""
return {"class_name": self.class_name(), **self.metadata.model_dump()}
def convert_chat_messages(self, messages: Sequence[ChatMessage]) -> List[Any]:
"""Convert chat messages to an LLM specific message format."""
converted_messages = []
for message in messages:
if isinstance(message.content, str):
converted_messages.append(message)
elif isinstance(message.content, List):
content_string = ""
for block in message.content:
if isinstance(block, TextBlock):
content_string += block.text
else:
raise ValueError("LLM only supports text inputs")
message.content = content_string
converted_messages.append(message)
else:
raise ValueError(f"Invalid message content: {message.content!s}")
return converted_messages
@abstractmethod
def chat(self, messages: Sequence[ChatMessage], **kwargs: Any) -> ChatResponse:
"""
Chat endpoint for LLM.
Args:
messages (Sequence[ChatMessage]):
Sequence of chat messages.
kwargs (Any):
Additional keyword arguments to pass to the LLM.
View on GitHub (pinned to afd0fef371)
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="...".
Example fix
# before msgs = [ChatMessage(blocks=[TextBlock(text="describe"), ImageBlock(image=bytes(...))], role=MessageRole.USER)] resp = text_only_llm.chat(msgs) # after msgs = [ChatMessage(content="describe", role=MessageRole.USER)] resp = text_only_llm.chat(msgs) # or switch to a multimodal LLM: Settings.llm = OpenAI(model="gpt-4o")
Defensive patterns
Strategy: validation
Validate before calling
from llama_index.core.base.llms.types import TextBlock texts = [b.text for b in msg.blocks if isinstance(b, TextBlock)] safe_msg = ChatMessage(content="\n".join(texts), role=msg.role)
Type guard
def is_text_only(msg: ChatMessage) -> bool:
return isinstance(msg.content, str) or all(
hasattr(b, "text") for b in (msg.blocks or [])
) Try / catch
try:
resp = llm.chat(msgs)
except ValueError as e:
if "text inputs" in str(e):
msgs = [strip_to_text(m) for m in msgs]
resp = llm.chat(msgs) Prevention
- Check model capability (multimodal or not) before building block lists.
- Keep one prompt path per modality rather than reusing multimodal messages everywhere.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid message content: {message.content!s}
- The provided image string is not base64-encoded
- image_node.image is neither a string or None.
- Could not format attribute {attribute_name} with value {temp
- resolve_image returned zero bytes
AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15).
Data as JSON: /api/errors/503f1f47cacb7279.
Report an issue: GitHub.