deepset-ai/haystack · error · ValueError
Assistant message must contain one text part at most.
Error message
Assistant message must contain one text part at most.
What it means
Assistant messages built from a template may include at most one TextContent part (alongside tool calls and reasoning). This error means two or more text parts were produced for one assistant message.
Source
Thrown at haystack/utils/jinja2_chat_extension.py:381
raise ValueError(
"User message must contain only TextContent, string, ImageContent or FileContent parts."
)
return ChatMessage.from_user(meta=meta, name=name, content_parts=valid_parts)
if role == "system":
if not isinstance(parts[0], TextContent):
raise ValueError("System message must contain a text part.")
text = parts[0].text
if len(parts) > 1:
raise ValueError("System message must contain only one text part.")
return ChatMessage.from_system(meta=meta, name=name, text=text)
if role == "assistant":
texts = [part.text for part in parts if isinstance(part, TextContent)]
tool_calls = [part for part in parts if isinstance(part, ToolCall)]
reasoning = [part for part in parts if isinstance(part, ReasoningContent)]
if len(texts) > 1:
raise ValueError("Assistant message must contain one text part at most.")
if len(texts) == 0 and len(tool_calls) == 0:
raise ValueError("Assistant message must contain at least one text or tool call part.")
if len(parts) > len(texts) + len(tool_calls) + len(reasoning):
raise ValueError("Assistant message must contain only text, tool call or reasoning parts.")
return ChatMessage.from_assistant(
meta=meta,
name=name,
text=texts[0] if texts else None,
tool_calls=tool_calls or None,
reasoning=reasoning[0] if reasoning else None,
)
if role == "tool":
tool_call_results = [part for part in parts if isinstance(part, ToolCallResult)]
if len(tool_call_results) == 0 or len(tool_call_results) > 1 or len(parts) > len(tool_call_results):
raise ValueError("Tool message must contain only one tool call result.")
tool_result = tool_call_results[0].resultView on GitHub (pinned to e318778c9b)
Solutions
- Merge the text into a single part: join strings before rendering or use {{ text_a ~ text_b }}.
- Insert only one text ChatMessage into the assistant block, or pre-merge messages.
- Split into multiple assistant ChatMessages if multiple texts are genuinely needed.
- Move extra text into tool call arguments or a following user/system message as appropriate.
Example fix
// before
{% insert %}{{ assistant_msg }}{% endinsert %}Extra text
// after
{{ assistant_msg.text ~ "\nExtra text" }} // single text part Defensive patterns
Strategy: validation
Validate before calling
from haystack.dataclasses import ChatMessage, TextContent
def validate_assistant_text_count(msg: ChatMessage):
texts = [p for p in msg.content_parts if isinstance(p, TextContent)]
if len(texts) > 1:
raise TypeError("Assistant message has more than one text part") Type guard
def has_at_most_one_text(msg: ChatMessage) -> bool:
return sum(isinstance(p, TextContent) for p in msg.content_parts) <= 1 Try / catch
try:
messages = renderer.run(template=tpl, variables=vars)["messages"]
except ValueError as e:
if "one text part at most" in str(e):
log.error("Assistant block produced multiple text parts; merge before rendering")
raise Prevention
- Join multiple assistant texts into one string before rendering.
- Insert at most one text ChatMessage per assistant block.
- Avoid emitting text both directly and via {% insert %} in the same block.
- Test templates that combine static text with inserted assistant messages.
When it happens
Trigger: An assistant block containing multiple text segments and/or multiple {% insert %} calls each yielding a text part; inserting a list of assistant messages into a single assistant message block.
Common situations: Templates that emit answer text plus an inserted explanation message into the same assistant turn; loops inside assistant blocks; converting multi-part assistant outputs from other frameworks.
Related errors
- Assistant message must contain at least one text or tool cal
- Assistant message must contain only text, tool call or reaso
- User message must contain only TextContent, string, ImageCon
- System message must contain a text part.
- System message must contain only one text part.
AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30).
Data as JSON: /api/errors/da1088427a1854a3.
Report an issue: GitHub.