spring-projects/spring-ai · error · java.lang.IllegalArgumentException

Single parameter must be of type ProgressNotification: {meth

Error message

Single parameter must be of type ProgressNotification: {method.getName()} in {method.getDeclaringClass().getName()} has parameter of type {parameters[0].getType().getName()}

What it means

For a single-parameter progress handler, the parameter must be assignable from ProgressNotification. A one-arg handler whose parameter is any other type (String, Double, a custom DTO) fails validation at registration with this IllegalArgumentException. The message template's {…} placeholders are literal; the offending type name is appended after the colon.

Source

Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/progress/AbstractMcpProgressMethodCallback.java:103

	 * @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 either 1 or 3 parameters
		if (parameters.length != 1 && parameters.length != 3) {
			throw new IllegalArgumentException(
					"Method must have either 1 parameter (ProgressNotification) or 3 parameters (Double, String, String): "
							+ method.getName() + " in " + method.getDeclaringClass().getName() + " has "
							+ parameters.length + " parameters");
		}

		// Check parameter types
		if (parameters.length == 1) {
			// Single parameter must be ProgressNotification
			if (!ProgressNotification.class.isAssignableFrom(parameters[0].getType())) {
				throw new IllegalArgumentException("Single parameter must be of type ProgressNotification: "
						+ method.getName() + " in " + method.getDeclaringClass().getName() + " has parameter of type "
						+ parameters[0].getType().getName());
			}
		}
		else {
			// Three parameters must be Double, String, String
			if (!Double.class.isAssignableFrom(parameters[0].getType())
					&& !double.class.isAssignableFrom(parameters[0].getType())) {
				throw new IllegalArgumentException("First parameter must be of type Double or double: "
						+ method.getName() + " in " + method.getDeclaringClass().getName() + " has parameter of type "
						+ parameters[0].getType().getName());
			}
			if (!String.class.isAssignableFrom(parameters[1].getType())) {
				throw new IllegalArgumentException("Second parameter must be of type String: " + method.getName()
						+ " in " + method.getDeclaringClass().getName() + " has parameter of type "
						+ parameters[1].getType().getName());
			}
			if (!String.class.isAssignableFrom(parameters[2].getType())) {

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Change the single parameter's type to ProgressNotification.
  2. Alternatively use the three-parameter form (Double, String, String) if you want primitive progress fields.
  3. Verify the import — use the MCP SDK's ProgressNotification, not a same-named class from another library.
  4. If you need richer data, wrap your custom payload into the handler body rather than the signature.

Example fix

// before
public void onProgress(String progressToken) { ... }
// after
public void onProgress(ProgressNotification notification) {
    String token = notification.progressToken();
    ...
}
Defensive patterns

Strategy: validation

Validate before calling

Parameter[] ps = handlerMethod.getParameters();
if (ps.length == 1 && !ProgressNotification.class.isAssignableFrom(ps[0].getType())) {
    throw new IllegalStateException("Single progress handler param must be ProgressNotification: " + handlerMethod);
}

Try / catch

try {
    registry.registerProgress(bean, method);
} catch (IllegalArgumentException e) {
    logger.error("Invalid progress handler parameter type: {}", e.getMessage());
}

Prevention

When it happens

Trigger: Registering onProgress(String token) or onProgress(MyCustomNotification n) as a single-parameter progress handler; validateParameters reaches the single-parameter branch and the isAssignableFrom check fails.

Common situations: Confusing the progress handler signature with the three-parameter (Double, String, String) variant; using a project-specific notification type instead of io.modelcontextprotocol.spec.ProgressNotification; auto-complete picking the wrong ProgressNotification import from another package.

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/de96f3e09ef95e2c. Report an issue: GitHub.