deepset-ai/haystack · error · ValueError

ChatMessages from {role} role must contain text. Received Ch

Error message

ChatMessages from {role} role must contain text. Received ChatMessage with no text: {message}

What it means

ChatPromptBuilder raises this in __init__ when a USER or SYSTEM ChatMessage passed as a Jinja template has text=None (e.g. a tool/function-call message with no textual content). Variable inference requires message.text to extract template variables, so the constructor fails fast.

Source

Thrown at haystack/components/builders/chat_prompt_builder.py:178

            `template` parameter. For example, to use more variables during prompt engineering than the ones present
            in the default template, you can provide them here.
        """
        self._variables = variables
        self._required_variables = required_variables
        self.template = template

        self._env = HaystackSandboxedEnvironment(extensions=[ChatMessageExtension])
        if arrow_import.is_successful():
            self._env.add_extension(Jinja2TimeExtension)

        extracted_variables = []
        if template and not variables:
            if isinstance(template, list):
                for message in template:
                    if message.is_from(ChatRole.USER) or message.is_from(ChatRole.SYSTEM):
                        # infer variables from template
                        if message.text is None:
                            raise ValueError(NO_TEXT_ERROR_MESSAGE.format(role=message.role.value, message=message))
                        if message.text and "templatize_part" in message.text:
                            raise ValueError(FILTER_NOT_ALLOWED_ERROR_MESSAGE)
                        assigned_variables, template_variables = _extract_template_variables_and_assignments(
                            env=self._env, template=message.text
                        )
                        extracted_variables += list(template_variables - assigned_variables)
            elif isinstance(template, str):
                assigned_variables, template_variables = _extract_template_variables_and_assignments(
                    env=self._env, template=template
                )
                extracted_variables = list(template_variables - assigned_variables)

        extracted_variables = extracted_variables or []
        self.variables = variables or extracted_variables
        self.required_variables = required_variables or []

        if len(self.variables) > 0 and required_variables is None:
            logger.warning(

View on GitHub (pinned to e318778c9b)

Solutions

  1. Ensure every USER/SYSTEM ChatMessage in the template list has non-None text (use ChatMessage.from_user(text=...) / from_system(text=...)).
  2. Filter out messages without text before passing the list to ChatPromptBuilder.
  3. If you need non-text content in a template, use a string template plus variables instead of ChatMessage objects.

Example fix

// before
msg = ChatMessage.from_function_call(call_obj)
prompt = ChatPromptBuilder(template=[msg])  # text is None
// after
template = [m for m in messages if m.text is not None and m.is_from(ChatRole.USER) or m.is_from(ChatRole.SYSTEM)]
prompt = ChatPromptBuilder(template=template)
Defensive patterns

Strategy: validation

Validate before calling

from haystack.dataclasses import ChatRole
msgs = [m for m in template if m.text is not None or not (m.is_from(ChatRole.USER) or m.is_from(ChatRole.SYSTEM))]

Type guard

def has_text(m) -> bool:
    return m.text is not None or not (m.is_from(ChatRole.USER) or m.is_from(ChatRole.SYSTEM))

Try / catch

try:
    builder = ChatPromptBuilder(template=template)
except ValueError as e:
    if 'must contain text' in str(e):
        template = [m for m in template if m.text is not None]
        builder = ChatPromptBuilder(template=template)
    else:
        raise

Prevention

When it happens

Trigger: Passing template as a list of ChatMessage where any USER or SYSTEM message was built without text content (e.g. ChatMessage.from_function_call or an empty message), then instantiating ChatPromptBuilder(template=[...]).

Common situations: Building a prompt list from deserialized or programmatically constructed messages where tool-call payloads replaced the text; copying messages from a chat log where the first system message has no text.

Related errors


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