{"record":{"id":"e694c68cd168426a","repo":"spring-projects/spring-ai","slug":"request-must-not-be-null-e694c6","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/sampling/SyncMcpSamplingMethodCallback.java","lineNumber":57,"sourceCode":"\tprivate SyncMcpSamplingMethodCallback(Builder builder) {\n\t\tsuper(builder.method, builder.bean);\n\t}\n\n\t/**\n\t * Apply the callback to the given request.\n\t * <p>\n\t * This method builds the arguments for the method call, invokes the method, and\n\t * returns the result.\n\t * @param request The sampling request, must not be null\n\t * @return The result of the method invocation\n\t * @throws McpSamplingMethodException if there is an error invoking the sampling\n\t * method\n\t * @throws IllegalArgumentException if the request is null\n\t */\n\t@Override\n\tpublic CreateMessageResult apply(CreateMessageRequest request) {\n\t\tif (request == null) {\n\t\t\tthrow new IllegalArgumentException(\"Request must not be null\");\n\t\t}\n\n\t\ttry {\n\t\t\t// Build arguments for the method call\n\t\t\tObject[] args = this.buildArgs(this.method, null, request);\n\n\t\t\t// Invoke the method\n\t\t\tthis.method.setAccessible(true);\n\t\t\tObject result = this.method.invoke(this.bean, args);\n\n\t\t\t// Return the result\n\t\t\treturn (CreateMessageResult) result;\n\t\t}\n\t\tcatch (Exception e) {\n\t\t\tthrow new McpSamplingMethodException(\"Error invoking sampling method: \" + this.method.getName(), e);\n\t\t}\n\t}\n","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/sampling/SyncMcpSamplingMethodCallback.java#L39-L75","documentation":"SyncMcpSamplingMethodCallback.apply() throws IllegalArgumentException when invoked with a null CreateMessageRequest. The callback immediately dereferences the request to build method arguments, so a null request is rejected up front with a clear message rather than a downstream NPE.","triggerScenarios":"Calling callback.apply(null) directly in unit tests or custom dispatch code; a transport layer passing a null request into the sampling handler chain.","commonSituations":"Hand-written tests probing callback behavior (e.g. testNullRequest); custom MCP server code invoking the callback outside the normal framework dispatch where requests are guaranteed non-null.","solutions":["Never call apply() manually with null; only invoke via the framework's sampling dispatch","In custom code, assert request != null before calling apply","If a test intentionally passes null, expect IllegalArgumentException and assert it"],"exampleFix":"// before\nCreateMessageResult r = callback.apply(null);\n// after\nif (request == null) {\n    throw new IllegalArgumentException(\"request required\");\n}\nCreateMessageResult r = callback.apply(request);","handlingStrategy":"validation","validationCode":"Objects.requireNonNull(request, \"CreateMessageRequest must not be null\");\nCreateMessageResult result = callback.apply(request);","typeGuard":null,"tryCatchPattern":"try { result = callback.apply(request); } catch (IllegalArgumentException e) { handleMissingRequest(e); }","preventionTips":["Only invoke sampling callbacks through the framework dispatch layer","Null-check request in custom dispatch wrappers","Assert non-null requests in integration tests before dispatch"],"tags":["null-check","sampling","sync"],"backgroundTag":"null-argument","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"}