deepset-ai/haystack · error · ValueError
user_prompt message block must have role 'user', found role
Error message
user_prompt message block must have role 'user', found role '{roles[0]}'. What it means
Raised when the first Jinja2 message block in user_prompt has a role other than 'user'. The Agent pipeline routes user_prompt through a builder expecting a user-role message, so any other role is rejected at init time.
Source
Thrown at haystack/components/agents/utils.py:257
# Regex to extract the role from a Jinja2 message block, e.g. {% message role="user" %}
_JINJA2_MESSAGE_ROLE_RE = re.compile(r'\{%\s*message\s+role\s*=\s*["\'](\w+)["\']')
def _validate_prompt_message_blocks(user_prompt: str | None, system_prompt: str | None) -> None:
"""
Validate explicit Jinja2 message blocks in Agent prompts.
:param user_prompt: Optional user prompt template.
:param system_prompt: Optional system prompt template.
:raises ValueError: If a prompt contains multiple message blocks or a literal block role is invalid.
"""
if user_prompt is not None:
message_blocks = _JINJA2_CHAT_TEMPLATE_RE.findall(user_prompt)
roles = _JINJA2_MESSAGE_ROLE_RE.findall(user_prompt)
if len(message_blocks) > 1:
raise ValueError(f"user_prompt must define exactly one message block, found {len(message_blocks)}.")
if roles and roles[0] != "user":
raise ValueError(f"user_prompt message block must have role 'user', found role '{roles[0]}'.")
if system_prompt is not None and _JINJA2_CHAT_TEMPLATE_RE.search(system_prompt):
message_blocks = _JINJA2_CHAT_TEMPLATE_RE.findall(system_prompt)
roles = _JINJA2_MESSAGE_ROLE_RE.findall(system_prompt)
if len(message_blocks) > 1:
raise ValueError(f"system_prompt must define exactly one message block, found {len(message_blocks)}.")
if roles and roles[0] != "system":
raise ValueError(f"system_prompt message block must have role 'system', found role '{roles[0]}'.")
def _template_for_role(prompt: str, role: str) -> str:
"""
Convert a prompt into a ChatPromptBuilder string template for the expected role.
:param prompt: Prompt template, with or without an explicit Jinja2 message block.
:param role: Role to use when wrapping a plain string prompt.
:returns: The original message-block template, or a plain string prompt wrapped in one message block.
"""View on GitHub (pinned to e318778c9b)
Solutions
- Change the message block role in user_prompt to 'user'.
- Move system-role content into system_prompt instead.
- Verify the user_prompt/system_prompt arguments were not swapped.
Example fix
// before
user_prompt = "{% message role='system' %}You are helpful.{% endmessage %}"
// after
system_prompt = "{% message role='system' %}You are helpful.{% endmessage %}"
user_prompt = "{% message role='user' %}{{ query }}{% endmessage %}" Defensive patterns
Strategy: validation
Validate before calling
roles = re.findall(r"{\%\s*message\s+role=['\"](\w+)['\"]", user_prompt)
assert not roles or roles[0] == "user", f"user_prompt role is {roles[0] if roles else None}" Try / catch
try:
agent = Agent(gen, user_prompt=prompt)
except ValueError as e:
if "role 'user'" in str(e):
logging.error("user_prompt wrong role: %s", e)
raise Prevention
- Hardcode role='user' inside user_prompt templates.
- Do not reuse system templates as user_prompt.
- Check argument order when constructing Agent.
When it happens
Trigger: Passing user_prompt like "{% message role='system' %}...{% endmessage %}" or role='assistant' to Agent's __init__.
Common situations: Copy-pasting a system message template into user_prompt; swapping user_prompt and system_prompt arguments; editing roles in a template without checking where it is used.
Related errors
- system_prompt message block must have role 'system', found r
- {prompt_label} must render to a {expected_role.value} messag
- user_prompt must define exactly one message block, found {le
- system_prompt must define exactly one message block, found {
- {prompt_label} must render to exactly one {expected_role.val
AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30).
Data as JSON: /api/errors/3dbb326ebc64f315.
Report an issue: GitHub.