deepset-ai/haystack · error · ValueError
System message must contain a text part.
Error message
System message must contain a text part.
What it means
A system-role message built from a template must start with a TextContent part. This error means the first part of the system message was a different content type, so Haystack cannot construct a valid system ChatMessage.
Source
Thrown at haystack/utils/jinja2_chat_extension.py:370
:param meta: The metadata of the message
:param name: The optional name of the message
:return: A ChatMessage object
:raises ValueError: If content parts don't allow to build a valid ChatMessage object or the role is not
supported
"""
if role == "user":
valid_parts = [part for part in parts if isinstance(part, (TextContent, str, ImageContent, FileContent))]
if len(parts) != len(valid_parts):
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,View on GitHub (pinned to e318778c9b)
Solutions
- Ensure the system message block contains plain text (or a ChatMessage.from_system) as its first content.
- Move images/files/tool content out of the system message into user/assistant/tool messages.
- Check that any {% insert %} inside the system block resolves to a system-role text ChatMessage.
- Simplify the system prompt template to static text plus text variables.
Example fix
// before
system: {% insert %}{{ image_message }}{% endinsert %}
// after
system: You are a helpful assistant. {{ instructions }} Defensive patterns
Strategy: validation
Validate before calling
from haystack.dataclasses import ChatMessage, TextContent
def validate_system_message(msg: ChatMessage):
parts = msg.content_parts
if not parts or not isinstance(parts[0], TextContent):
raise TypeError("System message must start with a TextContent part") Type guard
def is_text_first_system(msg: ChatMessage) -> bool:
return bool(msg.content_parts) and isinstance(msg.content_parts[0], TextContent) Try / catch
try:
messages = renderer.run(template=tpl, variables=vars)["messages"]
except ValueError as e:
if "System message must contain a text part" in str(e):
log.error("System block did not start with text; check inserted content")
raise Prevention
- Keep system prompt templates as plain text plus text variables.
- Never insert image/tool content into system message blocks.
- Only insert system-role text ChatMessages into system blocks.
- Review template diffs that touch system prompts.
When it happens
Trigger: A system message block whose rendered content resolves to a non-text part (e.g. an inserted message/image or a serialized content part) rather than plain text; using {% insert %} with an image-bearing message inside a system block.
Common situations: Accidentally placing image or tool content in the system prompt; template logic that inserts a variable that is not a text message at the start of the system block.
Related errors
- System message must contain only one text part.
- User message must contain only TextContent, string, ImageCon
- Assistant message must contain one text part at most.
- Assistant message must contain at least one text or tool cal
- Assistant message must contain only text, tool call or reaso
AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30).
Data as JSON: /api/errors/d4ed0ec6b0479c66.
Report an issue: GitHub.