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
- Change the single parameter's type to ProgressNotification.
- Alternatively use the three-parameter form (Double, String, String) if you want primitive progress fields.
- Verify the import — use the MCP SDK's ProgressNotification, not a same-named class from another library.
- 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
- Import ProgressNotification from the MCP SDK, not a similarly named class
- Use the three-param (Double, String, String) form if you want primitive fields
- Run registration tests in CI before deployment
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
- Method must have exactly 1 parameter (List<McpSchema.Resourc
- Method must have either 1 parameter (ProgressNotification) o
- URI variable parameters must be of type String: ${method} in
- Method must have exactly 1 parameter (List<McpSchema.Prompt>
- Parameter must be of type List<McpSchema.Prompt>:
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/de96f3e09ef95e2c.
Report an issue: GitHub.