{"record":{"id":"2f471d1f6f8b9986","repo":"spring-projects/spring-ai","slug":"method-must-not-be-null-2f471d","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/progress/AbstractMcpProgressMethodCallback.java","lineNumber":66,"sourceCode":"\t\tAssert.notNull(method, \"Method can't be null!\");\n\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 progress 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 progress callback.\n\t * This method should be implemented by subclasses to handle specific return type\n\t * 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 and\n\t * delegates exchange type checking to subclasses.","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/progress/AbstractMcpProgressMethodCallback.java#L48-L84","documentation":"AbstractMcpProgressMethodCallback.validateMethod rejects a null Method reference before performing signature validation. This is a defensive precondition: progress callbacks are built reflectively from an annotated method, and a null there indicates a programming error in the registration code, not a user-facing configuration problem.","triggerScenarios":"Calling a progress callback builder/constructor (e.g. AbstractMcpElicitationMethodCallback or a progress callback constructor) with null for the Method argument, typically because reflection lookup of the annotated method returned null (wrong method name, annotation not present).","commonSituations":"Looking up a method by name via Class.getMethod with a typo, catching the exception and passing null onward; building callbacks manually in tests; conditional registration code that skips annotation detection but still constructs the callback.","solutions":["Fix the upstream reflective lookup so it returns the actual Method (correct name and parameter types).","Assert non-null right after getMethod/getDeclaredMethod and fail with a descriptive message.","Prefer obtaining the Method from the annotation-scanning API instead of manual reflection.","In tests, pass Method XXX.class.getDeclaredMethod(\"name\", ParamType.class) rather than null placeholders."],"exampleFix":"// before\nMethod m = null; // lookup failed silently\nnew MyProgressCallback(bean, m);\n// after\nMethod m = bean.getClass().getDeclaredMethod(\"onProgress\", ProgressNotification.class);\nObjects.requireNonNull(m, \"progress handler method not found\");\nnew MyProgressCallback(bean, m);","handlingStrategy":"validation","validationCode":"Method m = bean.getClass().getDeclaredMethod(\"onProgress\", ProgressNotification.class);\nObjects.requireNonNull(m, \"progress handler method not found on \" + bean.getClass());","typeGuard":"static Method requireMethod(Class<?> type, String name, Class<?>... params) throws NoSuchMethodException {\n    return Objects.requireNonNull(type.getDeclaredMethod(name, params), \"method not found: \" + name);\n}","tryCatchPattern":"try {\n    new ProgressCallback(bean, method);\n} catch (IllegalArgumentException e) {\n    logger.error(\"Callback construction failed: {}\", e.getMessage());\n}","preventionTips":["Never pass Method variables that can be null into callback constructors","Handle NoSuchMethodException at the lookup site instead of swallowing it","Prefer annotation-scanning APIs over manual reflection"],"tags":["mcp","reflection","null-check","java"],"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"}