deepset-ai/haystack · error · TemplateSyntaxError

Role must be one of: {', '.join(self.SUPPORTED_ROLES)}

Error message

Role must be one of: {', '.join(self.SUPPORTED_ROLES)}

What it means

TemplateSyntaxError raised by `_parse_message_tag` when the role assigned to a {% message %} tag is a literal constant that is not in SUPPORTED_ROLES. Only a fixed set of chat roles (e.g. user, assistant, system, tool) are allowed for message templates.

Source

Thrown at haystack/utils/jinja2_chat_extension.py:189

        Parse the message tag and its attributes in the Jinja2 template.

        This method handles the parsing of role (mandatory), name (optional), meta (optional) and message body content.

        :param parser: The Jinja2 parser instance
        :param lineno: The line number of the tag, used for error reporting.
        :return: A CallBlock node containing the parsed message configuration
        :raises TemplateSyntaxError: If an invalid role is provided
        """

        # Parse role attribute (mandatory)
        parser.stream.expect("name:role")
        parser.stream.expect("assign")
        role_expr = parser.parse_expression()

        if isinstance(role_expr, nodes.Const):
            role = role_expr.value
            if role not in self.SUPPORTED_ROLES:
                raise TemplateSyntaxError(f"Role must be one of: {', '.join(self.SUPPORTED_ROLES)}", lineno)

        # Parse optional name attribute
        name_expr = None
        if parser.stream.current.test("name:name"):
            parser.stream.skip()
            parser.stream.expect("assign")
            name_expr = parser.parse_expression()
            if not isinstance(name_expr.value, str):
                raise TemplateSyntaxError("name must be a string", lineno)

        # Parse optional meta attribute
        meta_expr = None
        if parser.stream.current.test("name:meta"):
            parser.stream.skip()
            parser.stream.expect("assign")
            meta_expr = parser.parse_expression()
            if not isinstance(meta_expr, nodes.Dict):
                raise TemplateSyntaxError("meta must be a dictionary", lineno)

View on GitHub (pinned to e318778c9b)

Solutions

  1. Use a supported role literal, e.g. {% message role='user' %} or role='assistant'
  2. Inspect the extension's SUPPORTED_ROLES to see the exact allowed values
  3. Remove the role attribute to use the default if a custom role is unnecessary

Example fix

// before
{% message role='bot' %}Hi{% endmessage %}
// after
{% message role='assistant' %}Hi{% endmessage %}
Defensive patterns

Strategy: validation

Validate before calling

SUPPORTED_ROLES = {"user", "assistant", "system", "tool"}  # check the extension for exact set
assert role.lower() in SUPPORTED_ROLES, f"role must be one of {SUPPORTED_ROLES}"

Type guard

null

Try / catch

from jinja2.exceptions import TemplateSyntaxError
try:
    env.parse(template)
except TemplateSyntaxError as e:
    raise ValueError(f"Invalid role in template: {e.message}") from e

Prevention

When it happens

Trigger: Writing `{% message role='bot' %}` or `{% message role='Agent' %}` (wrong casing) or any other literal role not in SUPPORTED_ROLES in a chat template parsed by this Jinja2 extension.

Common situations: Using role names from other frameworks (OpenAI 'function', 'developer'); capitalized roles; typos like 'asistant'; hardcoding roles instead of relying on the default.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30). Data as JSON: /api/errors/4f8d896fbc375525. Report an issue: GitHub.