{"record":{"id":"8914d1ae82d166e8","repo":"deepset-ai/haystack","slug":"a-chatmessage-must-contain-at-least-one-textcon-8914d1","errorCode":null,"errorMessage":"A `ChatMessage` must contain at least one `TextContent`, `ToolCall`, `ToolCallResult`, or `ImageContent`.","messagePattern":"A `ChatMessage` must contain at least one `TextContent`, `ToolCall`, `ToolCallResult`, or `ImageContent`\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"haystack/utils/hf.py","lineNumber":73,"sourceCode":"    \"\"\"\n    Convert a message to the format expected by Hugging Face.\n\n    Note: ReasoningContent is skipped during conversion because the HuggingFace Inference API\n    (which follows the OpenAI-compatible chat completion format) does not support reasoning\n    in input messages. Reasoning is captured from model outputs for transparency but is not\n    sent back to the API in multi-turn conversations.\n    \"\"\"\n    text_contents = message.texts\n    tool_calls = message.tool_calls\n    tool_call_results = message.tool_call_results\n    images = message.images\n\n    # Filter out ReasoningContent from the content list for validation\n    # ReasoningContent is for human transparency only, not sent to the API\n    non_reasoning_content = [c for c in message._content if not isinstance(c, ReasoningContent)]\n\n    if not text_contents and not tool_calls and not tool_call_results and not images:\n        raise ValueError(\n            \"A `ChatMessage` must contain at least one `TextContent`, `ToolCall`, `ToolCallResult`, or `ImageContent`.\"\n        )\n    if len(tool_call_results) > 0 and len(non_reasoning_content) > 1:\n        raise ValueError(\n            \"For compatibility with the Hugging Face API, a `ChatMessage` with a `ToolCallResult` \"\n            \"cannot contain any other content.\"\n        )\n\n    # HF always expects a content field, even if it is empty\n    hf_msg: dict[str, Any] = {\"role\": message._role.value, \"content\": \"\"}\n\n    if tool_call_results:\n        result = tool_call_results[0]\n        hf_msg[\"content\"] = result.result\n        if tc_id := result.origin.id:\n            hf_msg[\"tool_call_id\"] = tc_id\n        # HF does not provide a way to communicate errors in tool invocations, so we ignore the error field\n        return hf_msg","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/deepset-ai/haystack/blob/e318778c9bf60a1963e3b5f451359655dd696c30/haystack/utils/hf.py#L55-L91","documentation":"ValueError raised in `convert_message_to_hf_format` when a ChatMessage's content list contains none of the content types the Hugging Face API can represent: TextContent, ToolCall, ToolCallResult, or ImageContent. ReasoningContent is deliberately excluded from this validation because it is for human transparency only and is never sent to the API, so a message containing only ReasoningContent is treated as empty.","triggerScenarios":"Calling convert_message_to_hf_format (or HuggingFaceAPIChatGenerator, which uses it) with a ChatMessage built solely from ReasoningContent, or from an empty content list, e.g. ChatMessage.from_assistant('') with no tool calls or images.","commonSituations":"Constructing assistant messages from LLM responses that contained only reasoning/thinking content; stripping content from a message during preprocessing; serializing placeholder messages.","solutions":["Ensure the ChatMessage contains at least one TextContent, ToolCall, ToolCallResult, or ImageContent before conversion","If the message only holds ReasoningContent, skip sending it to the generator or append a fallback TextContent","Use ChatMessage.from_assistant/from_user with non-empty content"],"exampleFix":"// before\nmsg = ChatMessage.from_assistant(\"\")  # or only ReasoningContent\nhf = convert_message_to_hf_format(msg)\n// after\nmsg = ChatMessage.from_assistant(\"Here is the answer.\")\nhf = convert_message_to_hf_format(msg)","handlingStrategy":"validation","validationCode":"from haystack.dataclasses import TextContent, ToolCall, ToolCallResult, ImageContent\nfrom haystack.utils import ReasoningContent\ndef is_hf_convertible(msg) -> bool:\n    return any(not isinstance(c, ReasoningContent) for c in msg._content)","typeGuard":"def has_sendable_content(msg) -> bool:\n    from haystack.dataclasses import TextContent, ToolCall, ToolCallResult, ImageContent\n    return any(isinstance(c, (TextContent, ToolCall, ToolCallResult, ImageContent)) for c in msg._content)","tryCatchPattern":"try:\n    hf_msg = convert_message_to_hf_format(msg)\nexcept ValueError:\n    hf_msg = None  # skip message or substitute a placeholder TextContent","preventionTips":["Never send messages containing only ReasoningContent to HF generators","Construct messages with ChatMessage.from_assistant/from_user with non-empty text","Filter out reasoning-only messages from the chat history before conversion"],"tags":["haystack","hugging-face","chatmessage","valueerror","empty-content"],"backgroundTag":"empty-message-content","analyzedSha":"e318778c9bf60a1963e3b5f451359655dd696c30","analyzedAt":"2026-08-30T11:45:20.711Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}