spring-projects/spring-ai · error · IllegalArgumentException
Method must have void return type:
Error message
Method must have void return type:
What it means
SyncMcpLoggingMethodCallback.validateReturnType requires the annotated sync logging consumer method to return void; any other return type triggers this IllegalArgumentException at registration, naming the method, declaring class, and actual return type. Sync consumers are fire-and-forget and cannot return values to the framework.
Source
Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/logging/SyncMcpLoggingMethodCallback.java:83
}
catch (Exception e) {
throw new McpLoggingConsumerMethodException(
"Error invoking logging consumer method: " + this.method.getName(), e);
}
}
/**
* Validates that the method return type is compatible with the logging 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 SyncMcpLoggingConsumerMethodCallback instances.
* <p>
* This builder provides a fluent API for constructing
* SyncMcpLoggingConsumerMethodCallback instances with the required parameters.
*/View on GitHub (pinned to 98a7beda4f)
Solutions
- Change the method to return void.
- If you need the async variant, use Mono<Void> with the async annotation/callback instead.
- Extract the logic into a void method and keep the value-returning method separate.
- Discard the return value explicitly by assigning to a local variable inside a void wrapper method.
Example fix
// before
public boolean handleLog(LoggingMessageNotification n) { log(n); return true; }
// after
public void handleLog(LoggingMessageNotification n) { log(n); } Defensive patterns
Strategy: validation
Validate before calling
if (handlerMethod.getReturnType() != void.class) {
throw new IllegalStateException("Sync @McpLogging handler must return void: " + handlerMethod);
} Try / catch
try {
registry.registerSyncLogging(bean, method);
} catch (IllegalArgumentException e) {
logger.error("Sync logging handler must be void: {}", e.getMessage());
} Prevention
- Use void return for sync handlers, Mono<Void> only for async
- Strip return values when porting async handlers to sync
- Check signatures whenever refactoring handler methods
When it happens
Trigger: Registering a method like boolean handleLog(LoggingMessageNotification n) or LoggingMessageNotification handleLog(...) with the sync MCP logging annotation; the callback constructor calls validateMethod and throws immediately.
Common situations: Reusing an existing method that returns a value as a logging consumer; porting an async Mono<Void> handler to the sync annotation without stripping the return; IDE auto-generated stubs returning Object.
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.getName() + "
- Method must have void return type:
- Method must have void or Mono<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/bc29be6ea214d15e.
Report an issue: GitHub.