spring-projects/spring-ai · error · IllegalArgumentException

Single parameter must be of type CreateMessageRequest: {meth

Error message

Single parameter must be of type CreateMessageRequest: {methodName} in {className} has parameter of type {paramTypeName}

What it means

With exactly one parameter, that parameter must be assignable from CreateMessageRequest, since it receives the sampling request. validateParameters() throws IllegalArgumentException when the single parameter has an incompatible type.

Source

Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/sampling/AbstractMcpSamplingMethodCallback.java:102

	 * delegates exchange type checking to subclasses.
	 * @param method The method to validate
	 * @throws IllegalArgumentException if the parameters are not compatible
	 */
	protected void validateParameters(Method method) {
		Parameter[] parameters = method.getParameters();

		// Check parameter count - must have at least 1 parameter
		if (parameters.length < 1) {
			throw new IllegalArgumentException(
					"Method must have at least 1 parameter (CreateMessageRequest): " + method.getName() + " in "
							+ method.getDeclaringClass().getName() + " has " + parameters.length + " parameters");
		}

		// Check parameter types
		if (parameters.length == 1) {
			// Single parameter must be CreateMessageRequest
			if (!CreateMessageRequest.class.isAssignableFrom(parameters[0].getType())) {
				throw new IllegalArgumentException("Single parameter must be of type CreateMessageRequest: "
						+ method.getName() + " in " + method.getDeclaringClass().getName() + " has parameter of type "
						+ parameters[0].getType().getName());
			}
		}
		else {
			// TODO: Support for multiple parameters corresponding to CreateMessageRequest
			// fields
			// For now, we only support the single parameter version
			throw new IllegalArgumentException(
					"Currently only methods with a single CreateMessageRequest parameter are supported: "
							+ method.getName() + " in " + method.getDeclaringClass().getName() + " has "
							+ parameters.length + " parameters");
		}
	}

	/**
	 * Builds the arguments array for invoking the method.
	 * <p>

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Change the single parameter type to CreateMessageRequest (or a subclass)
  2. If you need custom input parsing, accept CreateMessageRequest and map its fields manually inside the method
  3. Check the MCP SDK version's schema class (io.modelcontextprotocol.spec.McpSchema.CreateMessageRequest) and import the correct one

Example fix

// before
@McpSampling
public String sample(String request) { return "reply"; }
// after
@McpSampling
public String sample(CreateMessageRequest request) { return "reply"; }
Defensive patterns

Strategy: type-guard

Validate before calling

for (Method m : clazz.getDeclaredMethods()) {
    if (m.isAnnotationPresent(McpSampling.class)
            && m.getParameterCount() == 1
            && !CreateMessageRequest.class.isAssignableFrom(m.getParameterTypes()[0])) {
        throw new IllegalStateException(m.getName()
            + " parameter must be CreateMessageRequest, got "
            + m.getParameterTypes()[0].getName());
    }
}

Type guard

boolean hasCreateMessageRequestParam(Method m) {
    return m.getParameterCount() == 1
        && CreateMessageRequest.class.isAssignableFrom(m.getParameterTypes()[0]);
}

Try / catch

try {
    registerSamplingCallback(method);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Single parameter must be of type")) {
        log.error("Wrong parameter type on sampling method {}: {}", method, e.getMessage());
    } else { throw e; }
}

Prevention

When it happens

Trigger: Declaring a sampling callback like `void handler(String req)` or `void handler(MyCustomRequest req)` — a single parameter whose type is not CreateMessageRequest (or a subtype).

Common situations: Developers use their own request DTO, a String, or Map<String,Object> instead of the framework's CreateMessageRequest; or they upgraded spring-ai-mcp where the required request type changed.

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


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