spring-projects/spring-ai · error · IllegalArgumentException
Method must return either CompleteResult, CompleteCompletion
Error message
Method must return either CompleteResult, CompleteCompletion, List<String>, or String:
What it means
SyncMcpCompleteMethodCallback.validateReturnType throws this IllegalArgumentException at callback registration when a @McpComplete method's declared return type is not CompleteResult, CompleteCompletion, List, or String. This fails fast so invalid handlers are rejected before any request is served.
Source
Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/complete/SyncMcpCompleteMethodCallback.java:140
throw new IllegalArgumentException("Unsupported return type: " + result.getClass().getName());
}
/**
* Validates that the method return type is compatible with the complete 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();
boolean validReturnType = CompleteResult.class.isAssignableFrom(returnType)
|| CompleteCompletion.class.isAssignableFrom(returnType) || List.class.isAssignableFrom(returnType)
|| String.class.isAssignableFrom(returnType);
if (!validReturnType) {
throw new IllegalArgumentException(
"Method must return either CompleteResult, CompleteCompletion, List<String>, " + "or String: "
+ method.getName() + " in " + method.getDeclaringClass().getName() + " returns "
+ returnType.getName());
}
}
@Override
protected McpTransportContext resolveTransportContext(Object exchange) {
if (exchange instanceof McpSyncServerExchange e) {
return e.transportContext();
}
return null;
}
/**
* Create a new builder.
* @return A new builder instance
*/View on GitHub (pinned to 98a7beda4f)
Solutions
- Change the method to return CompleteResult, CompleteCompletion, List<String>, or String
- If the method computes something else, add a separate @McpComplete wrapper method that converts the result
- Check the import: use java.util.List and java.lang.String, not project-local classes with the same names
Example fix
// before
@McpComplete(promptName = "code")
public Map<String, Object> complete(String value) { return Map.of(); }
// after
@McpComplete(promptName = "code")
public List<String> complete(String value) { return List.of("java", "go"); } Defensive patterns
Strategy: validation
Validate before calling
for (Method m : bean.getClass().getDeclaredMethods()) {
if (m.isAnnotationPresent(McpComplete.class)) {
Class<?> rt = m.getReturnType();
if (!(CompleteResult.class.isAssignableFrom(rt) || CompleteCompletion.class.isAssignableFrom(rt)
|| List.class.isAssignableFrom(rt) || String.class.isAssignableFrom(rt)))
throw new IllegalStateException("bad @McpComplete return type on " + m.getName());
}
} Type guard
static boolean hasValidCompleteReturnType(Method m) {
Class<?> rt = m.getReturnType();
return CompleteResult.class.isAssignableFrom(rt) || CompleteCompletion.class.isAssignableFrom(rt)
|| List.class.isAssignableFrom(rt) || String.class.isAssignableFrom(rt);
} Try / catch
try { server.addCompletion(handler); }
catch (IllegalArgumentException e) { log.error("registration rejected: {}", e.getMessage()); throw e; } Prevention
- Only annotate methods returning CompleteResult, CompleteCompletion, List<String>, or String
- Run a startup self-check that scans @McpComplete methods before wiring the server
- Keep completion handlers small and dedicated rather than reusing tool methods
When it happens
Trigger: Annotating a method with @McpComplete whose return type is void, a Map, a custom DTO, an array type, or any other non-supported class; validation runs in the constructor during annotation scanning.
Common situations: Adding @McpComplete to an existing method with an unrelated return type, typos in imports pulling in the wrong String/List, or migrating a tool method to a completion method without changing its signature.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Method must return either CompleteResult, CompleteCompletion
- Method must have void or Mono<Void> return type:
- Method must have void return type: " + method.getName() + "
- Method must have void return type:
- Either prompt or uri must be provided!
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/7a09fd0bb68019b6.
Report an issue: GitHub.