{"record":{"id":"5f128884b716e4b8","repo":"deepset-ai/haystack","slug":"message-template-produced-content-that-couldn-t-be","errorCode":null,"errorMessage":"Message template produced content that couldn't be parsed into any message parts. Content: {content!r}","messagePattern":"Message template produced content that couldn't be parsed into any message parts\\. Content: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"haystack/utils/jinja2_chat_extension.py","lineNumber":242,"sourceCode":"        \"\"\"\n        Build a ChatMessage object from template content and serialize it to a JSON string.\n\n        This method is called by Jinja2 when processing a `{% message %}` tag.\n        It takes the rendered content from the template, converts XML blocks into ChatMessageContentT objects,\n        creates a ChatMessage object and serializes it to a JSON string.\n\n        :param role: The role of the message\n        :param name: Optional name for the message sender\n        :param meta: Optional metadata dictionary\n        :param caller: Callable that returns the rendered content\n        :return: A JSON string representation of the ChatMessage object\n        \"\"\"\n\n        content = caller()\n        start_tag, end_tag = _sentinel_tags(getattr(self.environment, _NONCE_ATTR))\n        parts = self._parse_content_parts(content, start_tag, end_tag)\n        if not parts:\n            raise ValueError(\n                f\"Message template produced content that couldn't be parsed into any message parts. \"\n                f\"Content: {_redact_nonce(content, start_tag, end_tag)!r}\"\n            )\n\n        chat_message = self._validate_build_chat_message(parts=parts, role=role, meta=meta, name=name)\n\n        return json.dumps(chat_message.to_dict()) + \"\\n\"\n\n    def _build_inserted_messages_json(\n        self,\n        messages: list[ChatMessage] | ChatMessage,\n        caller: Callable[[], str],  # noqa: ARG002\n    ) -> str:\n        \"\"\"\n        Expand a list of ChatMessage objects into newline-separated JSON, one message per line.\n\n        This method is called by Jinja2 when processing an `{% insert %}` tag. It produces the same JSON-line format\n        as `_build_chat_message_json`, so the messages are parsed back into ChatMessage objects by the","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/deepset-ai/haystack/blob/e318778c9bf60a1963e3b5f451359655dd696c30/haystack/utils/jinja2_chat_extension.py#L224-L260","documentation":"ValueError raised by `_build_chat_message_json` when a {% message %} template body renders to content that, after splitting on the internal sentinel tags, yields no parseable message parts. This means the template produced nothing recognizable (empty or only whitespace/non-part text) for the message.","triggerScenarios":"Rendering a {% message %} block whose body is empty or evaluates to an empty string (e.g. `{% message role='user' %}{{ optional }}{% endmessage %}` where optional is '' or None), or content that escapes the sentinel tagging so no parts match.","commonSituations":"Conditionally empty variables in the template body; templates where all content is inside {% if %} that evaluates false; overriding/sanitization that strips the sentinel tags so parsing finds no parts.","solutions":["Ensure the message body always renders at least one content part (text, image link, or tool part sentinel)","Guard empty variables with a Jinja default filter: {{ optional | default('fallback text') }}","Check that custom preprocessing/postprocessing does not strip or alter the sentinel tags produced by the extension"],"exampleFix":"// before\n{% message role='user' %}{{ maybe_empty }}{% endmessage %}\n// after\n{% message role='user' %}{{ maybe_empty | default('No question provided') }}{% endmessage %}","handlingStrategy":"try-catch","validationCode":"def message_body_is_renderable(template_body: str) -> bool:\n    return bool(template_body.strip())","typeGuard":"null","tryCatchPattern":"try:\n    messages = rendered_chat_prompt  # runs _build_chat_message_json internally\nexcept ValueError as e:\n    if \"couldn't be parsed into any message parts\" in str(e):\n        messages = [fallback_message]\n    else:\n        raise","preventionTips":["Ensure every {% message %} body renders non-empty content","Use Jinja default filters for potentially empty variables: {{ x | default('...') }}","Avoid bodies that collapse to whitespace under all conditional branches","Don't post-process rendered templates in ways that strip sentinel tags"],"tags":["haystack","jinja2","chatmessage","valueerror","template-render"],"backgroundTag":"empty-message-content","analyzedSha":"e318778c9bf60a1963e3b5f451359655dd696c30","analyzedAt":"2026-08-30T11:45:20.711Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}