spring-projects/spring-ai · error · IllegalArgumentException
Method parameters must be exchange, CompleteRequest, Complet
Error message
Method parameters must be exchange, CompleteRequest, CompleteArgument, or String: {method} in {class} has parameter of type {paramType} What it means
Thrown when a @McpComplete method parameter is not one of the allowed types: MCP exchange, McpTransportContext, McpSyncRequestContext/McpAsyncRequestContext, CompleteRequest, CompleteRequest.CompleteArgument, or String. Any other parameter type makes the method signature invalid for completion callbacks.
Source
Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/complete/AbstractMcpCompleteMethodCallback.java:254
}
hasExchangeParam = true;
}
else if (CompleteRequest.class.isAssignableFrom(paramType)) {
if (hasRequestParam) {
throw new IllegalArgumentException("Method cannot have more than one CompleteRequest parameter: "
+ method.getName() + " in " + method.getDeclaringClass().getName());
}
hasRequestParam = true;
}
else if (CompleteRequest.CompleteArgument.class.isAssignableFrom(paramType)) {
if (hasArgumentParam) {
throw new IllegalArgumentException("Method cannot have more than one CompleteArgument parameter: "
+ method.getName() + " in " + method.getDeclaringClass().getName());
}
hasArgumentParam = true;
}
else if (!String.class.isAssignableFrom(paramType)) {
throw new IllegalArgumentException(
"Method parameters must be exchange, CompleteRequest, CompleteArgument, or String: "
+ method.getName() + " in " + method.getDeclaringClass().getName()
+ " has parameter of type " + paramType.getName());
}
}
}
/**
* Builds the arguments array for invoking the method.
* <p>
* This method constructs an array of arguments based on the method's parameter types
* and the available values (exchange, request, argument).
* @param method The method to build arguments for
* @param exchangeOrContext The server exchange or transport context
* @param request The complete request
* @return An array of arguments for the method invocation
*/
protected Object[] buildArgs(Method method, Object exchangeOrContext, CompleteRequest request) {View on GitHub (pinned to 98a7beda4f)
Solutions
- Change unsupported parameters to allowed types (String for the value, plus at most one each of exchange/context/CompleteRequest/CompleteArgument)
- Remove extra parameters entirely if not needed
- Use @McpProgressToken or McpMeta only if that data is needed, as those are exempt from this check
Example fix
// before
@McpComplete(prompt="code")
public String complete(Integer index, CompleteRequest req) { ... }
// after
@McpComplete(prompt="code")
public String complete(CompleteRequest.CompleteArgument argument) { ... } Defensive patterns
Strategy: validation
Validate before calling
Set<Class<?>> allowed = Set.of(String.class, McpTransportContext.class, McpSyncRequestContext.class, McpAsyncRequestContext.class, CompleteRequest.class, CompleteRequest.CompleteArgument.class);
for (Class<?> t : m.getParameterTypes()) {
boolean ok = allowed.stream().anyMatch(a -> a.isAssignableFrom(t)) || t.isAnnotationPresent(McpProgressToken.class) || McpMeta.class.isAssignableFrom(t);
if (!ok) throw new IllegalStateException("Unsupported completion parameter type " + t.getName() + " in " + m);
} Type guard
boolean isAllowedCompletionParam(Class<?> t) {
return String.class.isAssignableFrom(t) || McpTransportContext.class.isAssignableFrom(t)
|| McpSyncRequestContext.class.isAssignableFrom(t) || McpAsyncRequestContext.class.isAssignableFrom(t)
|| CompleteRequest.class.isAssignableFrom(t) || CompleteRequest.CompleteArgument.class.isAssignableFrom(t);
} Try / catch
try {
callbackBuilder.build();
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("Method parameters must be")) { /* fix or remove the offending parameter type */ }
throw e;
} Prevention
- Only use String for the value being completed; completion methods do not accept arbitrary DTOs unlike @McpTool
- Copy signatures from official Spring AI MCP completion examples
- Keep a contract test listing allowed parameter types for all @McpComplete methods
When it happens
Trigger: Adding an arbitrary typed parameter (e.g. Integer, custom DTO, Map) to a @McpComplete method; forgetting that only String is accepted for the value being completed.
Common situations: Using tool-style signatures (custom input DTOs) in a completion method; IDE-generated signatures with wrong types; migrating from @McpTool annotations where richer parameter types are allowed.
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
- Parameter must be of type List<McpSchema.Resource>:
- Async complete methods should use McpAsyncRequestContext ins
- Sync complete methods should use McpSyncRequestContext inste
- Method cannot have more than one transport context parameter
- Method cannot have more than one exchange parameter: {method
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/636be7b64cdfb094.
Report an issue: GitHub.