spring-projects/spring-ai · error · McpResourceListChangedConsumerMethodException

Error invoking resource list changed consumer method: " + th

Error message

Error invoking resource list changed consumer method: " + this.method.getName()

What it means

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.

Source

Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/changed/resource/SyncMcpResourceListChangedMethodCallback.java:68

	 * the resource list changed consumer method
	 * @throws IllegalArgumentException if the updatedResources is null
	 */
	@Override
	public void accept(List<McpSchema.Resource> updatedResources) {
		if (updatedResources == null) {
			throw new IllegalArgumentException("Updated resources list must not be null");
		}

		try {
			// Build arguments for the method call
			Object[] args = this.buildArgs(this.method, null, updatedResources);

			// Invoke the method
			this.method.setAccessible(true);
			this.method.invoke(this.bean, args);
		}
		catch (Exception e) {
			throw new McpResourceListChangedConsumerMethodException(
					"Error invoking resource list changed consumer method: " + this.method.getName(), e);
		}
	}

	/**
	 * Validates that the method return type is compatible with the resource list changed
	 * consumer callback.
	 * @param method The method to validate
	 * @throws IllegalArgumentException if the return type is not compatible
	 */
	@Override
	protected void validateReturnType(Method method) {
		Class<?> returnType = method.getReturnType();

		if (returnType != void.class) {
			throw new IllegalArgumentException("Method must have void return type: " + method.getName() + " in "
					+ method.getDeclaringClass().getName() + " returns " + returnType.getName());
		}

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Inspect getCause() of McpResourceListChangedConsumerMethodException for the actual failure and fix that code.
  2. Open the callback method's package to spring-ai (add opens/exports in module-info or --add-opens) if setAccessible fails.
  3. Add try/catch or defensive checks inside the consumer method so it does not propagate runtime exceptions.

Example fix

// before
public void onResourcesChanged(List<McpSchema.Resource> r) { parse(r.get(0)); }
// after
public void onResourcesChanged(List<McpSchema.Resource> r) { if (r != null && !r.isEmpty()) parse(r.get(0)); }
Defensive patterns

Strategy: try-catch

Validate before calling

Method m = bean.getClass().getMethod("onResourcesChanged", List.class);
m.setAccessible(true); // fail fast if JPMS blocks access
Objects.requireNonNull(bean);

Try / catch

try {
    callback.accept(resources);
} catch (McpResourceListChangedConsumerMethodException e) {
    log.error("Resource-list-changed handler '{}' failed", e.getMessage(), e.getCause());
}

Prevention

When it happens

Trigger: 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).

Common situations: User code inside the callback throws (NPE, downstream call failure); Java module system blocks setAccessible on the method's package.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/ce6aab1a942b05eb. Report an issue: GitHub.