spring-projects/spring-ai · error · IllegalArgumentException

Updated resources list must not be null

Error message

Updated resources list must not be null

What it means

SyncMcpResourceListChangedMethodCallback.accept(List<McpSchema.Resource>) rejects a null updatedResources list with IllegalArgumentException before invoking the consumer method. The library treats null as an invalid notification payload rather than an empty change set.

Solutions

  1. Pass an empty List (List.of() / Collections.emptyList()) instead of null when no resources exist.
  2. Null-check the notification payload before invoking accept().
  3. If this comes from a custom transport, normalize null lists to empty lists at the transport layer.

Example fix

// before
callback.accept(null);
// after
callback.accept(updatedResources == null ? List.of() : updatedResources);
Defensive patterns

Strategy: validation

Validate before calling

if (updatedResources == null) { updatedResources = List.of(); }

Type guard

static List<McpSchema.Resource> orEmpty(List<McpSchema.Resource> l) {
    return l == null ? List.of() : l;
}

Try / catch

try {
    callback.accept(updatedResources);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("Updated resources list must not be null")) {
        log.warn("Received null resources payload; treating as empty");
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling accept(null) directly, or a server/notification path delivering a resource-list-changed event with a null resources list into a sync callback.

Common situations: Custom or test harness code simulating resource change notifications and passing null instead of an empty list.

Related errors


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

Appendix: source

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

		implements Consumer<List<McpSchema.Resource>> {

	private SyncMcpResourceListChangedMethodCallback(Builder builder) {
		super(builder.method, builder.bean);
	}

	/**
	 * Accept the resource list change notification and process it.
	 * <p>
	 * This method builds the arguments for the method call and invokes the method.
	 * @param updatedResources The updated list of resources, must not be null
	 * @throws McpResourceListChangedConsumerMethodException if there is an error invoking
	 * 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

View on GitHub (pinned to 98a7beda4f)