zed-industries/zed · error

Only tool result should be extracted

Error message

Only tool result should be extracted

What it means

When converting Zed's internal message representation into an Ollama chat request, the code maps message content parts to Ollama message types. Tool-result content parts are expected to be filtered/extracted earlier in the conversion; if any other content-part variant reaches this match arm, the code declares it a logic error and panics with 'Only tool result should be extracted'.

Solutions

  1. Update the Ollama provider's `to_ollama_request` to map the new content-part variant to the appropriate Ollama message type.
  2. Filter non-tool-result parts before this match so only tool results are extracted, mirroring how other providers do it.
  3. Log and skip unrecognized parts instead of panicking, so chats with mixed content degrade gracefully.

Example fix

// before
_ => unreachable!("Only tool result should be extracted"),
// after
other => {
    log::warn!("skipping unsupported content part in ollama request: {other:?}");
    continue;
}
Defensive patterns

Strategy: fallback

Validate before calling

// validate message contents before building the request
let unsupported: Vec<_> = msg.content.iter().filter(|p| !matches!(p, MessageContent::ToolResult(_))).collect();
if !unsupported.is_empty() { /* log and skip or return an error */ }

Type guard

fn is_tool_result(part: &MessageContent) -> bool {
    matches!(part, MessageContent::ToolResult(_))
}

Try / catch

// the panic is unreachable!(); wrap request building at the boundary
let request = std::panic::catch_unwind(|| to_ollama_request(&messages)).map_err(|_| anyhow!("ollama request conversion failed"))?;

Prevention

When it happens

Trigger: Streaming a completion whose request message contains a content part that is neither handled upstream nor a tool result — e.g. a `ToolUse` or image/text variant reaching the extraction branch in `to_ollama_request` because the assistant/user message wasn't normalized first.

Common situations: New `MessageContent` variants added to the language model protocol without updating the Ollama provider conversion; requests built from conversation history containing unmatched tool-call/tool-result pairs.

Related errors


AI-assisted analysis of zed-industries/zed@916fc2b8cb (2026-09-19). Data as JSON: /api/errors/c8caadb9a489bc49. Report an issue: GitHub.

Appendix: source

Thrown at crates/language_models/src/provider/ollama.rs:407

                        .extract_if(.., |x| matches!(x, MessageContent::ToolResult(..)))
                    {
                        match tool_result {
                            MessageContent::ToolResult(tool_result) => {
                                let images = tool_result
                                    .images()
                                    .map(|image| image.source.to_string())
                                    .collect::<Vec<_>>();
                                messages.push(ChatMessage::Tool {
                                    tool_name: tool_result.tool_name.to_string(),
                                    content: tool_result.text_contents(),
                                    images: if images.is_empty() {
                                        None
                                    } else {
                                        Some(images)
                                    },
                                })
                            }
                            _ => unreachable!("Only tool result should be extracted"),
                        }
                    }
                    if !msg.content.is_empty() {
                        messages.push(ChatMessage::User {
                            content: msg.string_contents(),
                            images: if images.is_empty() {
                                None
                            } else {
                                Some(images)
                            },
                        })
                    }
                }
                Role::Assistant => {
                    let mut text_content = String::new();
                    let mut thinking = None;
                    let mut tool_calls = Vec::new();
                    for content in msg.content.into_iter() {

View on GitHub (pinned to 916fc2b8cb)