spring-projects/spring-ai · error · IllegalArgumentException
Method must return Mono<CreateMessageResult> or CreateMessag
Error message
Method must return Mono<CreateMessageResult> or CreateMessageResult: {methodName} in {className} returns {returnTypeName} What it means
AsyncMcpSamplingMethodCallback.validateReturnType throws IllegalArgumentException when a method registered as an async sampling callback does not return Mono<CreateMessageResult> or a CreateMessageResult subtype. The async callback path must be able to treat the outcome reactively or wrap it directly, so any other return type is rejected at callback construction time.
Source
Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/sampling/AsyncMcpSamplingMethodCallback.java:102
}
}
catch (Exception e) {
return Mono
.error(new McpSamplingMethodException("Error invoking sampling method: " + this.method.getName(), e));
}
}
/**
* Validates that the method return type is compatible with the sampling 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 (!Mono.class.isAssignableFrom(returnType) && !CreateMessageResult.class.isAssignableFrom(returnType)) {
throw new IllegalArgumentException(
"Method must return Mono<CreateMessageResult> or CreateMessageResult: " + method.getName() + " in "
+ method.getDeclaringClass().getName() + " returns " + returnType.getName());
}
}
/**
* Checks if a parameter type is compatible with the exchange type.
* @param paramType The parameter type to check
* @return true if the parameter type is compatible with the exchange type, false
* otherwise
*/
@Override
protected boolean isExchangeType(Class<?> paramType) {
// No exchange type for sampling methods
return false;
}
/**View on GitHub (pinned to 98a7beda4f)
Solutions
- Change the method to return Mono<CreateMessageResult> (wrap a plain result with Mono.just)
- Or return CreateMessageResult directly if a synchronous response is acceptable in this path
- Verify with method.getReturnType() before registering
Example fix
// before
CreateMessageResult sample(CreateMessageRequest req) { ... }
// after
Mono<CreateMessageResult> sample(CreateMessageRequest req) {
return Mono.just(doSample(req));
} Defensive patterns
Strategy: validation
Validate before calling
Class<?> rt = method.getReturnType();
if (!Mono.class.isAssignableFrom(rt) && !CreateMessageResult.class.isAssignableFrom(rt)) {
throw new IllegalArgumentException(method + " must return Mono<CreateMessageResult> or CreateMessageResult");
} Try / catch
try { builder.build(); } catch (IllegalArgumentException e) { log.error("Async sampling return type invalid: {}", e.getMessage()); } Prevention
- Annotate async sampling methods with explicit Mono<CreateMessageResult> signatures
- Add a startup-time reflection check over all registered sampling methods
- Keep sync and async handler methods in separate classes to avoid signature drift
When it happens
Trigger: Registering an @McpSampling-annotated method (or manually built AsyncMcpSamplingMethodCallback) whose signature returns e.g. String, void, or Flux<CreateMessageResult>, then building the callback.
Common situations: Writing a sampling handler method and forgetting the reactive wrapper; copying a sync callback method (returns CreateMessageResult-only sibling contract) into an async specification; upgrading from sync to async specs without changing return types.
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
- Mono return type must be Mono<Void>: {method.getName()} in {
- Method must return CreateMessageResult: {methodName} in {cla
- Expected reactive return type but got: {resultClassName|null
- ASYNC Providers don't support imperative (non-reactive) retu
- SYNC Providers don't support reactive return types. Skipping
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/0f4efe6e0d1bd1f5.
Report an issue: GitHub.