{"record":{"id":"62f32a06ff9a4d09","repo":"spring-projects/spring-ai","slug":"error-calling-tool","errorCode":null,"errorMessage":"Error calling tool: ","messagePattern":"Error calling tool: ","errorType":"exception","errorClass":"ToolExecutionException","httpStatus":null,"severity":"error","filePath":"mcp/common/src/main/java/org/springframework/ai/mcp/AsyncMcpToolCallback.java","lineNumber":155,"sourceCode":"\t\t\t}).contextWrite(ctx -> ctx.putAll(ToolCallReactiveContextHolder.getContext())).block();\n\t\t}\n\t\tcatch (McpError ex) {\n\t\t\tlogger.error(\"Protocol error while calling tool: \", ex);\n\t\t\t// Since the tool calling manager only handles ToolExecutionException, this\n\t\t\t// bubbles up and fails the model interaction.\n\t\t\tthrow ex;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tlogger.error(\"Exception while tool calling: \", ex);\n\t\t\tthrow new ToolExecutionException(this.getToolDefinition(), ex);\n\t\t}\n\t\tAssert.notNull(response, \"response was null\");\n\n\t\tif (response.isError() != null && response.isError()) {\n\t\t\tif (logger.isErrorEnabled()) {\n\t\t\t\tlogger.error(\"Error calling tool: \" + response.content());\n\t\t\t}\n\t\t\tthrow new ToolExecutionException(this.getToolDefinition(),\n\t\t\t\t\tnew IllegalStateException(\"Error calling tool: \" + response.content()));\n\t\t}\n\t\treturn jsonHelper.toJson(response.content());\n\t}\n\n\t/**\n\t * Creates a builder for constructing AsyncMcpToolCallback instances.\n\t * @return a new builder\n\t */\n\tpublic static Builder builder() {\n\t\treturn new Builder();\n\t}\n\n\t/**\n\t * Builder for constructing AsyncMcpToolCallback instances.\n\t */\n\tpublic static final class Builder {\n","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/common/src/main/java/org/springframework/ai/mcp/AsyncMcpToolCallback.java#L137-L173","documentation":"AsyncMcpToolCallback.call() wraps any error reported by the remote MCP server's tool response into a ToolExecutionException. The MCP protocol lets a tool return a successful response whose isError flag is set with the error message in content(); the library surfaces that server-side failure to the caller rather than returning the content as a normal result. The message text after the prefix is the server-provided error content.","triggerScenarios":"Calling an async MCP tool via AsyncMcpToolCallback.call(String, ToolContext) where the McpAsyncClient's CallToolResult has isError()==true — i.e. the remote tool executed but returned a protocol-level error (bad tool input, tool-internal exception, missing tool on server).","commonSituations":"MCP server tool validates arguments and rejects them; the tool implementation on the server throws and the server returns the exception message as error content; calling a tool name that no longer exists on the server after a server upgrade; passing arguments that fail the server tool's JSON schema.","solutions":["Inspect the exception's cause/content message to see the server-side error text and fix the arguments passed to the tool","Verify the tool name and its input schema against the current MCP server (list tools) — the server may have been upgraded or the tool removed","Check MCP server logs; the error content often originates from a server-side exception","Retry with corrected input; if the server is misbehaving, restart or fix the MCP server tool"],"exampleFix":"// before\ncallback.call(\"{\\\"city\\\": \\\"\" + userInput + \"\\\"}\", null);\n// after\n// validate input against the tool's schema and handle the protocol error\ndefinition = callback.getToolDefinition();\ntry {\n    return callback.call(jsonSchemaValidate(definition.inputSchema(), userInputJson), null);\n} catch (ToolExecutionException e) {\n    log.error(\"MCP tool {} rejected the call: {}\", definition.name(), e.getCause().getMessage());\n    throw e;\n}","handlingStrategy":"try-catch","validationCode":"ToolDefinition def = callback.getToolDefinition();\nJsonSchemaValidator.validateOrThrow(def.inputSchema(), argumentsJson); // pre-validate input against the advertised schema","typeGuard":"boolean isErrorResult(CallToolResult r) { return r != null && Boolean.TRUE.equals(r.isError()); }","tryCatchPattern":"try {\n    String out = asyncToolCallback.call(inputJson, toolContext);\n} catch (ToolExecutionException e) {\n    logger.warn(\"MCP tool {} failed: {}\", e.getToolDefinition().name(), e.getCause().getMessage());\n    // surface to user or fall back\n}","preventionTips":["Validate tool arguments against the tool's inputSchema before calling","Re-fetch tool definitions when the MCP server version changes","Log the server error content from the cause to speed diagnosis","Add timeouts so a misbehaving server cannot hang the call"],"tags":["mcp","tool-execution","remote-server"],"backgroundTag":"tool-execution-failed","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}