{"record":{"id":"d4ed0ec6b0479c66","repo":"deepset-ai/haystack","slug":"system-message-must-contain-a-text-part","errorCode":null,"errorMessage":"System message must contain a text part.","messagePattern":"System message must contain a text part\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"haystack/utils/jinja2_chat_extension.py","lineNumber":370,"sourceCode":"        :param meta: The metadata of the message\n        :param name: The optional name of the message\n        :return: A ChatMessage object\n\n        :raises ValueError: If content parts don't allow to build a valid ChatMessage object or the role is not\n                            supported\n        \"\"\"\n\n        if role == \"user\":\n            valid_parts = [part for part in parts if isinstance(part, (TextContent, str, ImageContent, FileContent))]\n            if len(parts) != len(valid_parts):\n                raise ValueError(\n                    \"User message must contain only TextContent, string, ImageContent or FileContent parts.\"\n                )\n            return ChatMessage.from_user(meta=meta, name=name, content_parts=valid_parts)\n\n        if role == \"system\":\n            if not isinstance(parts[0], TextContent):\n                raise ValueError(\"System message must contain a text part.\")\n            text = parts[0].text\n            if len(parts) > 1:\n                raise ValueError(\"System message must contain only one text part.\")\n            return ChatMessage.from_system(meta=meta, name=name, text=text)\n\n        if role == \"assistant\":\n            texts = [part.text for part in parts if isinstance(part, TextContent)]\n            tool_calls = [part for part in parts if isinstance(part, ToolCall)]\n            reasoning = [part for part in parts if isinstance(part, ReasoningContent)]\n            if len(texts) > 1:\n                raise ValueError(\"Assistant message must contain one text part at most.\")\n            if len(texts) == 0 and len(tool_calls) == 0:\n                raise ValueError(\"Assistant message must contain at least one text or tool call part.\")\n            if len(parts) > len(texts) + len(tool_calls) + len(reasoning):\n                raise ValueError(\"Assistant message must contain only text, tool call or reasoning parts.\")\n            return ChatMessage.from_assistant(\n                meta=meta,\n                name=name,","sourceCodeStart":352,"sourceCodeEnd":388,"githubUrl":"https://github.com/deepset-ai/haystack/blob/e318778c9bf60a1963e3b5f451359655dd696c30/haystack/utils/jinja2_chat_extension.py#L352-L388","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nsystem: {% insert %}{{ image_message }}{% endinsert %}\n// after\nsystem: You are a helpful assistant. {{ instructions }}","handlingStrategy":"validation","validationCode":"from haystack.dataclasses import ChatMessage, TextContent\n\ndef validate_system_message(msg: ChatMessage):\n    parts = msg.content_parts\n    if not parts or not isinstance(parts[0], TextContent):\n        raise TypeError(\"System message must start with a TextContent part\")","typeGuard":"def is_text_first_system(msg: ChatMessage) -> bool:\n    return bool(msg.content_parts) and isinstance(msg.content_parts[0], TextContent)","tryCatchPattern":"try:\n    messages = renderer.run(template=tpl, variables=vars)[\"messages\"]\nexcept ValueError as e:\n    if \"System message must contain a text part\" in str(e):\n        log.error(\"System block did not start with text; check inserted content\")\n    raise","preventionTips":["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."],"tags":["chat-template","message-validation","system-prompt"],"backgroundTag":"invalid-message-content-part","analyzedSha":"e318778c9bf60a1963e3b5f451359655dd696c30","analyzedAt":"2026-08-30T11:45:20.711Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}