spring-projects/spring-ai · error
Method must have void return type: " + method.getName() + "
Error message
Method must have void return type: " + method.getName() + " in " + method.getDeclaringClass().getName() + " returns " + returnType.getName()
What it means
Sync resource-list-changed callback methods must return void. This IllegalArgumentException is thrown at registration by validateReturnType when the method returns any other type. Sync callbacks cannot report results, so non-void returns are rejected.
Source
Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/changed/resource/SyncMcpResourceListChangedMethodCallback.java:84
}
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());
}
}
/**
* Create a new builder.
* @return A new builder instance
*/
public static Builder builder() {
return new Builder();
}
/**
* Builder for creating SyncMcpResourceListChangedMethodCallback instances.
* <p>
* This builder provides a fluent API for constructing
* SyncMcpResourceListChangedMethodCallback instances with the required parameters.
*/View on GitHub (pinned to 98a7beda4f)
Solutions
- Change the method's return type to void for the sync callback.
- If reactive handling is needed, register the method with the async callback (Mono<Void> allowed) instead.
- Move side-effect results into internal fields/logging rather than the return value.
Example fix
// before
public boolean onResourcesChanged(List<McpSchema.Resource> r) { ...; return true; }
// after
public void onResourcesChanged(List<McpSchema.Resource> r) { ... } Defensive patterns
Strategy: validation
Validate before calling
if (m.getReturnType() != void.class) throw new IllegalStateException("sync resource-list-changed callback must return void"); Type guard
static boolean hasValidSyncReturnType(Method m) {
return m.getReturnType() == void.class;
} Try / catch
try {
registry.register(syncCallback);
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("Method must have void return type")) {
throw new IllegalStateException("Sync callback must be declared void", e);
}
throw e;
} Prevention
- Declare sync handlers as void; use the async callback when you need Mono<Void>.
- Avoid sharing one method between sync and async registrations unless it returns void and you only need sync semantics.
When it happens
Trigger: Registering a sync (SyncMcpResourceListChangedMethodCallback) callback whose return type is boolean, String, Mono, or any other non-void type.
Common situations: Sharing one handler method between sync and async registrations (async needs Mono<Void>), or returning a status value the developer expects the framework to log.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Method must have void or Mono<Void> return type:
- Method must have void return type:
- Method must have void or Mono<Void> return type:
- Method must have void return type:
- Method must have exactly 1 parameter (List<McpSchema.Resourc
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/6c7d80388243b209.
Report an issue: GitHub.