zed-industries/zed · error
Google AI does not support custom tool calls
Error message
Google AI does not support custom tool calls
What it means
When translating a message history into Google AI (Gemini) request parts, a ToolUse block must carry LanguageModelToolUseInput::Json. Gemini function calling only accepts structured JSON arguments, so a custom (string) tool input cannot be mapped and the conversion bails with this message before a request is sent.
Source
Thrown at crates/google_ai/src/completion.rs:63
thought: true,
thought_signature: Some(signature),
}));
}
}
MessageContent::Thinking { .. } => {}
MessageContent::RedactedThinking(_) | MessageContent::Compaction(_) => {}
MessageContent::Image(image) => {
mapped_parts.push(Part::InlineDataPart(InlineDataPart {
inline_data: GenerativeContentBlob {
mime_type: "image/png".to_string(),
data: image.source.to_string(),
},
}));
}
MessageContent::ToolUse(tool_use) => {
let thought_signature = tool_use.thought_signature.filter(|s| !s.is_empty());
let LanguageModelToolUseInput::Json(input) = tool_use.input else {
anyhow::bail!("Google AI does not support custom tool calls");
};
mapped_parts.push(Part::FunctionCallPart(crate::FunctionCallPart {
function_call: crate::FunctionCall {
name: tool_use.name.to_string(),
args: input,
id: Some(tool_use.id.to_string()),
},
thought_signature,
}));
}
MessageContent::ToolResult(tool_result) => {
let mut text_output = String::new();
let mut images: Vec<InlineDataPart> = Vec::new();
for part in tool_result.content {
match part {
language_model_core::LanguageModelToolResultContent::Text(text) => {
text_output.push_str(&text);View on GitHub (pinned to 5a9b9558db)
Solutions
- Declare tools with a JSON object input schema so tool calls always produce Json input
- Normalize history before mapping: convert custom text input into JSON (e.g. {"input": text}) or drop incompatible turns with a warning
- If a tool genuinely takes text, wrap it in a single-field JSON object
Example fix
// before
let LanguageModelToolUseInput::Json(input) = tool_use.input else {
anyhow::bail!("Google AI does not support custom tool calls");
};
// after: coerce custom text into JSON so history still maps
let input = match tool_use.input {
LanguageModelToolUseInput::Json(input) => input,
LanguageModelToolUseInput::Custom(text) => serde_json::json!({ "input": text }),
}; Defensive patterns
Strategy: type-guard
Validate before calling
// before mapping history into a Google AI request
for message in &messages {
for part in &message.content {
if let MessageContent::ToolUse(tool_use) = part {
anyhow::ensure!(
matches!(tool_use.input, LanguageModelToolUseInput::Json(_)),
"tool '{}' has non-JSON input; Google AI cannot replay it",
tool_use.name
);
}
}
} Type guard
fn is_google_compatible_tool_use(tool_use: &ToolUse) -> bool {
matches!(tool_use.input, LanguageModelToolUseInput::Json(_))
} Prevention
- Define tool input schemas as JSON objects from the start
- Normalize cross-provider transcripts: convert or strip custom tool inputs before dispatch
- When conversion fails, name the offending tool id in the error to speed debugging
When it happens
Trigger: Streaming to Google AI a conversation that contains tool_use blocks created by another provider or code path that used custom/string tool input; any MessageContent::ToolUse whose input is not the Json variant while building the GenerateContent payload.
Common situations: Switching models mid-conversation to Gemini after tools ran with string inputs; replaying cross-provider transcripts through the Google AI backend; older tool definitions whose arguments were raw text.
Related errors
- User content must contain at least one part
- Model must be specified
- Request must contain at least one content item
- Failed to connect to Ollama API: {} {}
AI-assisted analysis of zed-industries/zed@5a9b9558db (2026-08-20).
Data as JSON: /api/errors/51764060d05e835d.
Report an issue: GitHub.