{"record":{"id":"39856c710465a357","repo":"spring-projects/spring-ai","slug":"error-calling-tool-39856c","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/SyncMcpToolCallback.java","lineNumber":154,"sourceCode":"\t\tcatch (McpError ex) {\n\t\t\t// A protocol-level error indicates the tool invocation itself failed and\n\t\t\t// must not be conveyed to the model. Rethrow it as a hard failure, mirroring\n\t\t\t// how @Tool treats checked exceptions and Errors. Since the tool calling\n\t\t\t// manager only handles ToolExecutionException, this bubbles up and fails the\n\t\t\t// model interaction.\n\t\t\tlogger.error(\"Protocol error while calling tool: \", ex);\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\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 {@code SyncMcpToolCallback} 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 {@code SyncMcpToolCallback} instances.\n\t */\n\tpublic static final class Builder {\n","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/common/src/main/java/org/springframework/ai/mcp/SyncMcpToolCallback.java#L136-L172","documentation":"SyncMcpToolCallback.call() wraps any error reported by the remote MCP server's tool response into a ToolExecutionException. MCP tools can return a CallToolResult with isError()==true while the transport call itself succeeded; the library treats that as a failed execution and surfaces the server-provided content as the message. The text after 'Error calling tool: ' is the server's own error description.","triggerScenarios":"Calling a sync MCP tool via SyncMcpToolCallback.call(String functionInput, ToolContext) where the McpSyncClient.callTool(...) result has isError()==true (server rejected args, tool threw, or tool name unknown on the server).","commonSituations":"Sending tool arguments that fail the server-side JSON schema validation; the remote tool implementation raised an exception whose message the server returned as content; the tool was renamed/removed on the server between listing and calling; MCP server version exposes an incompatible tool schema.","solutions":["Read the cause message (the server content) and correct the tool arguments accordingly","Re-list tools from the MCP server and confirm the tool name and input schema still match what your code sends","Check the MCP server logs for the underlying exception inside the tool implementation","Retry after fixing input or restarting/repairing the MCP server"],"exampleFix":"// before\nString result = toolCallback.call(argumentsJson, toolContext);\n// after\ntry {\n    String result = toolCallback.call(argumentsJson, toolContext);\n} catch (ToolExecutionException e) {\n    String serverError = e.getCause().getMessage(); // e.g. \"Error calling tool: Invalid arguments: missing 'city'\"\n    throw new IllegalStateException(\"Tool \" + e.getToolDefinition().name() + \" failed: \" + serverError, e);\n}","handlingStrategy":"try-catch","validationCode":"ToolDefinition def = toolCallback.getToolDefinition();\nJsonSchemaValidator.validateOrThrow(def.inputSchema(), argumentsJson); // fail fast on client side\n// also: ensure def.name() still exists in a fresh listTools() result from the server","typeGuard":"boolean isErrorResult(CallToolResult r) { return r != null && Boolean.TRUE.equals(r.isError()); }","tryCatchPattern":"try {\n    return toolCallback.call(inputJson, toolContext);\n} catch (ToolExecutionException e) {\n    String serverMsg = e.getCause() != null ? e.getCause().getMessage() : \"\";\n    throw new IllegalStateException(\"MCP tool call failed: \" + serverMsg, e);\n}","preventionTips":["Validate arguments against the tool's inputSchema before invoking","Confirm tool name/schema via listTools after any server upgrade","Capture and log the server error content embedded in the exception cause","Run in try-catch so a protocol-level tool error doesn't crash the chat pipeline"],"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-14T05:17:10.506Z"}