{"record":{"id":"480c81ee1cbd7474","repo":"spring-projects/spring-ai","slug":"method-must-not-be-null-480c81","errorCode":null,"errorMessage":"Method must not be null","messagePattern":"Method 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/changed/resource/AbstractMcpResourceListChangedMethodCallback.java","lineNumber":69,"sourceCode":"\t\tAssert.notNull(bean, \"Bean can't be null!\");\n\n\t\tthis.method = method;\n\t\tthis.bean = bean;\n\t\tthis.validateMethod(this.method);\n\t}\n\n\t/**\n\t * Validates that the method signature is compatible with the resource list changed\n\t * consumer callback.\n\t * <p>\n\t * This method checks that the return type is valid and that the parameters match the\n\t * expected pattern.\n\t * @param method The method to validate\n\t * @throws IllegalArgumentException if the method signature is not compatible\n\t */\n\tprotected void validateMethod(Method method) {\n\t\tif (method == null) {\n\t\t\tthrow new IllegalArgumentException(\"Method must not be null\");\n\t\t}\n\n\t\tthis.validateReturnType(method);\n\t\tthis.validateParameters(method);\n\t}\n\n\t/**\n\t * Validates that the method return type is compatible with the resource list changed\n\t * consumer callback. This method should be implemented by subclasses to handle\n\t * specific return type validation.\n\t * @param method The method to validate\n\t * @throws IllegalArgumentException if the return type is not compatible\n\t */\n\tprotected abstract void validateReturnType(Method method);\n\n\t/**\n\t * Validates method parameters. This method provides common validation logic.\n\t * @param method The method to validate","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/changed/resource/AbstractMcpResourceListChangedMethodCallback.java#L51-L87","documentation":"IllegalArgumentException thrown by AbstractMcpResourceListChangedMethodCallback.validateMethod() when a null Method is passed during callback construction. validateMethod runs from the constructor (null check first, then return-type and parameter validation), so any builder/registration path that fails to resolve the handler's reflective Method hits this before any signature checks.","triggerScenarios":"Constructing a resource-list-changed callback (sync or async subclass) with method(null), or a reflective lookup (getDeclaredMethod/getMethod) returning null being passed through unchecked. The constructor is the caller, so this surfaces at object creation time.","commonSituations":"Method-name/signature lookups failing after a refactor or SDK upgrade; manual builder wiring omitting the method; conditional method resolution returning null in test harnesses; annotation metadata missing so the scanner yields null.","solutions":["Pass the resolved java.lang.reflect.Method of the @McpResourceListChanged handler to the builder/constructor.","Check that the reflective lookup used the correct method name and parameter types and asserted non-null before constructing the callback.","Rely on the annotation-driven registration path so the framework resolves the method automatically.","Add an Objects.requireNonNull(method) assertion at the lookup site to fail with a clearer message."],"exampleFix":"// before\nMethod m = clazz.getDeclaredMethod(\"onResourcesChanged\"); // wrong params -> null passed on / lookup throws\ncallbackBuilder.method(m);\n// after\nMethod m = clazz.getDeclaredMethod(\"onResourcesChanged\", List.class);\nObjects.requireNonNull(m, \"resource list changed handler not found\");\ncallbackBuilder.method(m);","handlingStrategy":"validation","validationCode":"Method m = clazz.getDeclaredMethod(\"onResourcesChanged\", List.class);\nObjects.requireNonNull(m, \"resource list changed handler method not found on \" + clazz.getName());\nnew MyResourceListChangedCallback(m, bean);","typeGuard":null,"tryCatchPattern":"try {\n    callback = new SyncMcpResourceListChangedMethodCallback(method, bean);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"Method must not be null\")) {\n        throw new ConfigurationException(\"Resource list changed method resolution failed — check name/signature\", e);\n    }\n    throw e;\n}","preventionTips":["Assert reflective lookups non-null before constructing callbacks.","Update method lookups together with handler refactors.","Prefer annotation scanning over manual Method resolution."],"tags":["mcp","null-method","builder-validation","resource-callback"],"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"}