{"record":{"id":"462d6a1ac62293e3","repo":"spring-projects/spring-ai","slug":"request-must-not-be-null-462d6a","errorCode":null,"errorMessage":"Request must not be null","messagePattern":"Request must not be null","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/tool/AbstractSyncMcpToolMethodCallback.java","lineNumber":89,"sourceCode":"\t * @return A CallToolResult representing the error\n\t */\n\tprotected CallToolResult createSyncErrorResult(Exception e) {\n\t\tThrowable rootCause = findCauseUsingPlainJava(e);\n\t\treturn CallToolResult.builder()\n\t\t\t.isError(true)\n\t\t\t.addTextContent(e.getMessage() + System.lineSeparator() + rootCause.getMessage())\n\t\t\t.build();\n\t}\n\n\t/**\n\t * Validates that the request is not null. This is a synchronous wrapper around the\n\t * parent class's reactive validation.\n\t * @param request The request to validate\n\t * @throws IllegalArgumentException if the request is null\n\t */\n\tprotected void validateSyncRequest(CallToolRequest request) {\n\t\tif (request == null) {\n\t\t\tthrow new IllegalArgumentException(\"Request must not be null\");\n\t\t}\n\t}\n\n}\n","sourceCodeStart":71,"sourceCodeEnd":94,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/tool/AbstractSyncMcpToolMethodCallback.java#L71-L94","documentation":"AbstractSyncMcpToolMethodCallback.validateSyncRequest guards the entry of every synchronous MCP tool method callback. Before dispatching a @McpTool annotated method it verifies that the incoming McpAnnotationUtils-wrapped CallToolRequest is present; a null request cannot be executed, so an IllegalArgumentException is thrown immediately. This is an internal programming-contract check, not a user-input validation.","triggerScenarios":"Calling any code path that invokes a sync MCP tool callback (e.g. call(McpTransportContext, CallToolRequest)) with a null CallToolRequest, or framework/transport layers that forward a missing request object.","commonSituations":"Custom transport or router code that builds tool-call invocations programmatically and forgets to construct the CallToolRequest; tests that call the callback directly with null; version mismatches where an upstream layer passes null after an API change.","solutions":["Ensure a non-null CallToolRequest is constructed (McpSchema.CallToolRequest.builder().name(toolName).arguments(args).build()) before invoking the callback.","If calling from custom code, add a null check / Objects.requireNonNull on the request before dispatching to the tool callback.","Check for framework version alignment (spring-ai mcp modules all on the same version) so internal layers never pass null."],"exampleFix":"// before\ncallback.call(context, null);\n\n// after\nMcpSchema.CallToolRequest request = McpSchema.CallToolRequest.builder()\n    .name(\"myTool\")\n    .arguments(Map.of(\"param\", \"value\"))\n    .build();\ncallback.call(context, request);","handlingStrategy":"validation","validationCode":"if (request == null) {\n    throw new IllegalArgumentException(\"CallToolRequest must be built before invoking the tool callback\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always construct CallToolRequest via its builder before invoking a tool callback.","Use Objects.requireNonNull at your dispatch layer's entry point.","Keep all spring-ai mcp module versions aligned to avoid internal null-passing regressions."],"tags":["null-argument","mcp","tool-callback","illegal-argument"],"backgroundTag":"null-argument","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"}