{"record":{"id":"ce6aab1a942b05eb","repo":"spring-projects/spring-ai","slug":"error-invoking-resource-list-changed-consumer-meth","errorCode":null,"errorMessage":"Error invoking resource list changed consumer method: \" + this.method.getName()","messagePattern":"Error invoking resource list changed consumer method: \" \\+ this\\.method\\.getName\\(\\)","errorType":"exception","errorClass":"McpResourceListChangedConsumerMethodException","httpStatus":null,"severity":"error","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/changed/resource/SyncMcpResourceListChangedMethodCallback.java","lineNumber":68,"sourceCode":"\t * the resource list changed consumer method\n\t * @throws IllegalArgumentException if the updatedResources is null\n\t */\n\t@Override\n\tpublic void accept(List<McpSchema.Resource> updatedResources) {\n\t\tif (updatedResources == null) {\n\t\t\tthrow new IllegalArgumentException(\"Updated resources list 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, updatedResources);\n\n\t\t\t// Invoke the method\n\t\t\tthis.method.setAccessible(true);\n\t\t\tthis.method.invoke(this.bean, args);\n\t\t}\n\t\tcatch (Exception e) {\n\t\t\tthrow new McpResourceListChangedConsumerMethodException(\n\t\t\t\t\t\"Error invoking resource list changed consumer method: \" + this.method.getName(), e);\n\t\t}\n\t}\n\n\t/**\n\t * Validates that the method return type is compatible with the resource list changed\n\t * consumer callback.\n\t * @param method The method to validate\n\t * @throws IllegalArgumentException if the return type is not compatible\n\t */\n\t@Override\n\tprotected void validateReturnType(Method method) {\n\t\tClass<?> returnType = method.getReturnType();\n\n\t\tif (returnType != void.class) {\n\t\t\tthrow new IllegalArgumentException(\"Method must have void return type: \" + method.getName() + \" in \"\n\t\t\t\t\t+ method.getDeclaringClass().getName() + \" returns \" + returnType.getName());\n\t\t}","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/changed/resource/SyncMcpResourceListChangedMethodCallback.java#L50-L86","documentation":"When reflective invocation of the sync resource-list-changed consumer method fails (IllegalAccessException, InvocationTargetException wrapping any user-code exception, etc.), the library wraps the cause in McpResourceListChangedConsumerMethodException with this message. The real cause is the attached 'e' exception.","triggerScenarios":"The registered consumer method throws any exception at invocation, is inaccessible (setAccessible denied by security/JPMS), or its declaring bean is in a bad state (e.g. closed client).","commonSituations":"User code inside the callback throws (NPE, downstream call failure); Java module system blocks setAccessible on the method's package.","solutions":["Inspect getCause() of McpResourceListChangedConsumerMethodException for the actual failure and fix that code.","Open the callback method's package to spring-ai (add opens/exports in module-info or --add-opens) if setAccessible fails.","Add try/catch or defensive checks inside the consumer method so it does not propagate runtime exceptions."],"exampleFix":"// before\npublic void onResourcesChanged(List<McpSchema.Resource> r) { parse(r.get(0)); }\n// after\npublic void onResourcesChanged(List<McpSchema.Resource> r) { if (r != null && !r.isEmpty()) parse(r.get(0)); }","handlingStrategy":"try-catch","validationCode":"Method m = bean.getClass().getMethod(\"onResourcesChanged\", List.class);\nm.setAccessible(true); // fail fast if JPMS blocks access\nObjects.requireNonNull(bean);","typeGuard":null,"tryCatchPattern":"try {\n    callback.accept(resources);\n} catch (McpResourceListChangedConsumerMethodException e) {\n    log.error(\"Resource-list-changed handler '{}' failed\", e.getMessage(), e.getCause());\n}","preventionTips":["Keep callback method bodies defensive: null/empty checks before dereferencing.","Add --add-opens or module-info opens if the handler lives in a strongly-encapsulated module.","Wrap risky downstream calls inside the handler with their own error handling."],"tags":["java","mcp","reflection","wrapped-exception","invocation"],"backgroundTag":"internal-invariant-violation","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"}