zed-industries/zed · error · anyhow::Error
DeepSeek does not support custom tools
Error message
DeepSeek does not support custom tools
What it means
into_deepseek rejects any LanguageModelRequest with contains_custom_tool_input() before building the OpenAI-compatible chat request: DeepSeek's API only accepts function tools with JSON schemas, so the freeform custom-tool variant cannot be mapped to a tool entry.
Source
Thrown at crates/language_models/src/provider/deepseek.rs:366
Err(error) => return async move { Err(error.into()) }.boxed(),
};
let stream = self.stream_completion(request, cx);
async move {
let mapper = DeepSeekEventMapper::new();
Ok(mapper.map_stream(stream.await?).boxed())
}
.boxed()
}
}
pub fn into_deepseek(
request: LanguageModelRequest,
model: &deepseek::Model,
max_output_tokens: Option<u64>,
) -> Result<deepseek::Request> {
if request.contains_custom_tool_input() {
anyhow::bail!("DeepSeek does not support custom tools");
}
let thinking = deepseek_thinking(model, request.thinking_allowed);
let thinking_enabled = thinking
.as_ref()
.is_some_and(|thinking| thinking.kind == deepseek::ThinkingType::Enabled);
let mut messages = Vec::new();
let mut current_reasoning: Option<String> = None;
for message in request.messages {
for content in message.content {
match content {
MessageContent::Text(text) => {
let should_add = if message.role == Role::User {
!text.trim().is_empty()
} else {
!text.is_empty()View on GitHub (pinned to f4178619ac)
Solutions
- Convert the tool to a function tool with a JSON Schema input
- Disable the custom tool/extension when the active model is DeepSeek
- Use a provider whose API supports custom tools for that workflow
- Check the request's tools with contains_custom_tool_input() before dispatch
Defensive patterns
Strategy: validation
Validate before calling
if model.provider() == "deepseek" && request.contains_custom_tool_input() {
return Err(anyhow!("DeepSeek requires function tools; re-register '{}' with a JSON schema", tool_name));
} Type guard
fn is_function_only_request(request: &LanguageModelRequest) -> bool {
!request.contains_custom_tool_input()
} Try / catch
match into_deepseek(request, model, max_tokens) {
Ok(req) => Ok(client.complete(req).await?),
Err(e) if e.to_string().contains("custom tools") => { request.tools.clear_of_custom(); into_deepseek(request, model, max_tokens) }
Err(e) => Err(e),
} Prevention
- Prefer function tools everywhere; custom tools are a per-provider extension
- Validate tool kinds against the selected model's capabilities before sending
- Surface a UI-level warning when a custom tool is active on an incompatible model
When it happens
Trigger: Using a DeepSeek model (deepseek-chat/reasoner via Zed's provider integration) while an agent or extension attaches a custom tool to the request.
Common situations: Switching an existing agent from Anthropic/OpenAI to DeepSeek without re-checking tool types; extensions that always register their tool as Custom.
Related errors
- Bedrock does not support custom tools
- llama.cpp does not support custom tools
- LM Studio does not support custom tools
- Failed to connect to DeepSeek API: {} {}
- $ref target not found in {defs_key}: {ref_str}
AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20).
Data as JSON: /api/errors/58ec4b62382a8063.
Report an issue: GitHub.