deepset-ai/haystack · error · ValueError

For compatibility with the Hugging Face API, a `ChatMessage`

Error message

For compatibility with the Hugging Face API, a `ChatMessage` with a `ToolCallResult` cannot contain any other content.

What it means

ValueError raised in `convert_message_to_hf_format` when a ChatMessage contains a ToolCallResult together with any other non-reasoning content. The Hugging Face chat API requires a message that carries a tool result to contain only that result, so mixing it with text, tool calls, or images is rejected.

Source

Thrown at haystack/utils/hf.py:77

    (which follows the OpenAI-compatible chat completion format) does not support reasoning
    in input messages. Reasoning is captured from model outputs for transparency but is not
    sent back to the API in multi-turn conversations.
    """
    text_contents = message.texts
    tool_calls = message.tool_calls
    tool_call_results = message.tool_call_results
    images = message.images

    # Filter out ReasoningContent from the content list for validation
    # ReasoningContent is for human transparency only, not sent to the API
    non_reasoning_content = [c for c in message._content if not isinstance(c, ReasoningContent)]

    if not text_contents and not tool_calls and not tool_call_results and not images:
        raise ValueError(
            "A `ChatMessage` must contain at least one `TextContent`, `ToolCall`, `ToolCallResult`, or `ImageContent`."
        )
    if len(tool_call_results) > 0 and len(non_reasoning_content) > 1:
        raise ValueError(
            "For compatibility with the Hugging Face API, a `ChatMessage` with a `ToolCallResult` "
            "cannot contain any other content."
        )

    # HF always expects a content field, even if it is empty
    hf_msg: dict[str, Any] = {"role": message._role.value, "content": ""}

    if tool_call_results:
        result = tool_call_results[0]
        hf_msg["content"] = result.result
        if tc_id := result.origin.id:
            hf_msg["tool_call_id"] = tc_id
        # HF does not provide a way to communicate errors in tool invocations, so we ignore the error field
        return hf_msg

    # Handle multimodal content (text + images) preserving order
    if text_contents or images:
        content_parts: list[dict[str, Any]] = []

View on GitHub (pinned to e318778c9b)

Solutions

  1. Split the message: put the ToolCallResult in its own ChatMessage and move other content into a separate message
  2. Strip other content parts before conversion when only the tool result should be sent
  3. Use ChatMessage.from_tool_call_result (or the appropriate constructor) so only the result is in the content list

Example fix

// before
msg = ChatMessage(_role="tool", _content=[ToolCallResult(...), TextContent("done")])
// after
result_msg = ChatMessage(_role="tool", _content=[ToolCallResult(...)])
text_msg = ChatMessage.from_assistant("done")
Defensive patterns

Strategy: validation

Validate before calling

def is_tool_result_only(msg) -> bool:
    from haystack.dataclasses import ToolCallResult
    results = [c for c in msg._content if isinstance(c, ToolCallResult)]
    return len(results) == 0 or len(msg._content) == len(results)

Type guard

def can_convert_with_tool_result(msg) -> bool:
    from haystack.dataclasses import ToolCallResult
    has_result = any(isinstance(c, ToolCallResult) for c in msg._content)
    return not has_result or len(msg._content) == 1

Try / catch

try:
    hf_msg = convert_message_to_hf_format(msg)
except ValueError:
    # split: emit result-only message, handle other parts separately
    hf_msg = convert_message_to_hf_format(result_only_message(msg))

Prevention

When it happens

Trigger: Calling convert_message_to_hf_format with a message whose content list has a ToolCallResult plus, e.g., a TextContent or ToolCall (len(tool_call_results) > 0 and len(non_reasoning_content) > 1), which typically happens when merging tool output and explanation into a single message.

Common situations: Aggregating a tool's result and assistant commentary into one ChatMessage; frameworks that append ToolCallResult to an existing message instead of creating a separate one; multi-tool pipelines that batch results.

Related errors


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