{"record":{"id":"fa5d2e2b95e6f62e","repo":"zed-industries/zed","slug":"openrouter-does-not-support-custom-tool-calls","errorCode":null,"errorMessage":"OpenRouter does not support custom tool calls","messagePattern":"OpenRouter does not support custom tool calls","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/language_models/src/provider/open_router.rs","lineNumber":482,"sourceCode":"\n    // Anthropic models via OpenRouter don't accept reasoning_details being echoed back\n    // in requests - it's an output-only field for them. However, Gemini models require\n    // the thought signatures to be echoed back for proper reasoning chain continuity.\n    // Note: OpenRouter's model API provides an `architecture.tokenizer` field (e.g. \"Claude\",\n    // \"Gemini\") which could replace this ID prefix check, but since this is the only place\n    // we need this distinction, we're just using this less invasive check instead.\n    // If we ever have a more formal distionction between the models in the future,\n    // we should revise this to use that instead.\n    let is_anthropic_model = model.id().starts_with(\"anthropic/\");\n    let session_id = open_router_session_id(request.thread_id);\n\n    let mut messages = Vec::new();\n    let mut any_message_wants_cache = false;\n    let mut last_cache_message_index: Option<usize> = None;\n\n    for message in request.messages {\n        let mut message_added_content = false;\n        let reasoning_details_for_message = if is_anthropic_model {\n            None\n        } else {\n            message.reasoning_details.clone()\n        };\n\n        let message_wants_cache = message.cache;\n        if message_wants_cache {\n            any_message_wants_cache = true;\n        }\n\n        for content in message.content {\n            match content {\n                MessageContent::Text(text) => {\n                    add_message_content_part(\n                        open_router::MessagePart::Text {\n                            text,\n                            cache_control: None,\n                        },","sourceCodeStart":464,"sourceCodeEnd":500,"githubUrl":"https://github.com/zed-industries/zed/blob/5a9b9558db01a6b906cec2fb70a797affdc58cdd/crates/language_models/src/provider/open_router.rs#L464-L500","documentation":"Raised in into_open_router when converting a message that contains a custom/tool call content kind OpenRouter's schema cannot represent. It is a capability gap sentinel: the OpenRouter provider does not support custom tool calls, so the request cannot be serialized.","triggerScenarios":"Thrown at crates/language_models/src/provider/open_router.rs:485 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Disable custom tools for OpenRouter models","Route through a provider/model combination that supports custom tool input"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"5a9b9558db01a6b906cec2fb70a797affdc58cdd","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}