spring-projects/spring-ai · error · IllegalArgumentException

Method cannot have more than one CompleteArgument parameter:

Error message

Method cannot have more than one CompleteArgument parameter: {method} in {class}

What it means

Thrown while validating an @McpComplete-annotated method's signature: validateParameters detected that the method declares more than one parameter typed as the complete-argument type (CompleteArgument). The same duplicate-parameter guard pattern used for other supported types fires here — the argument-binding flag was already set when a second CompleteArgument parameter was encountered, so the framework cannot bind a single completion argument to two parameters.

Source

Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/complete/AbstractMcpCompleteMethodCallback.java:248

				hasTransportContext = true;
			}
			else if (isExchangeType(paramType)) {
				if (hasExchangeParam) {
					throw new IllegalArgumentException("Method cannot have more than one exchange parameter: "
							+ method.getName() + " in " + method.getDeclaringClass().getName());
				}
				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).

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Remove the duplicate CompleteArgument parameter, keeping one
  2. Rebuild the callback

Example fix

// before
public String complete(CompleteArgument a1, CompleteArgument a2) { ... }
// after
public String complete(CompleteArgument argument) { ... }
Defensive patterns

Strategy: validation

Validate before calling

long a = Arrays.stream(m.getParameterTypes()).filter(CompleteRequest.CompleteArgument.class::isAssignableFrom).count();
if (a > 1) throw new IllegalStateException("Only one CompleteArgument parameter allowed: " + m);

Try / catch

try {
    callbackBuilder.build();
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("more than one CompleteArgument")) { /* keep a single CompleteArgument */ }
    throw e;
}

Prevention

When it happens

Trigger: A method signature includes two parameters assignable to CompleteRequest.CompleteArgument.

Common situations: Copy-paste signatures; declaring the argument both directly and inside another wrapper the developer also annotated.

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


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/577290c68ac612f8. Report an issue: GitHub.