{"record":{"id":"1d2e97ad6a43f3b2","repo":"spring-projects/spring-ai","slug":"single-parameter-must-be-of-type-elicitrequest","errorCode":null,"errorMessage":"Single parameter must be of type ElicitRequest: ","messagePattern":"Single parameter must be of type ElicitRequest: ","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/elicitation/AbstractMcpElicitationMethodCallback.java","lineNumber":102,"sourceCode":"\t * delegates exchange type checking to subclasses.\n\t * @param method The method to validate\n\t * @throws IllegalArgumentException if the parameters are not compatible\n\t */\n\tprotected void validateParameters(Method method) {\n\t\tParameter[] parameters = method.getParameters();\n\n\t\t// Check parameter count - must have at least 1 parameter\n\t\tif (parameters.length < 1) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"Method must have at least 1 parameter (ElicitRequest): \" + method.getName() + \" in \"\n\t\t\t\t\t\t\t+ method.getDeclaringClass().getName() + \" has \" + parameters.length + \" parameters\");\n\t\t}\n\n\t\t// Check parameter types\n\t\tif (parameters.length == 1) {\n\t\t\t// Single parameter must be ElicitRequest\n\t\t\tif (!ElicitRequest.class.isAssignableFrom(parameters[0].getType())) {\n\t\t\t\tthrow new IllegalArgumentException(\"Single parameter must be of type ElicitRequest: \" + method.getName()\n\t\t\t\t\t\t+ \" in \" + method.getDeclaringClass().getName() + \" has parameter of type \"\n\t\t\t\t\t\t+ parameters[0].getType().getName());\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// TODO: Support for multiple parameters corresponding to ElicitRequest\n\t\t\t// fields\n\t\t\t// For now, we only support the single parameter version\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"Currently only methods with a single ElicitRequest parameter are supported: \" + method.getName()\n\t\t\t\t\t\t\t+ \" in \" + method.getDeclaringClass().getName() + \" has \" + parameters.length\n\t\t\t\t\t\t\t+ \" parameters\");\n\t\t}\n\t}\n\n\t/**\n\t * Builds the arguments array for invoking the method.\n\t * <p>","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/elicitation/AbstractMcpElicitationMethodCallback.java#L84-L120","documentation":"Thrown by AbstractMcpElicitationMethodCallback.validateParameters when an @McpElicitation-annotated method declares exactly one parameter whose type is not (a subtype of) ElicitRequest. The elicitation callback framework invokes handler methods reflectively with a single McpSchema.ElicitRequest argument, so a single-parameter method must accept it.","triggerScenarios":"Registering an elicitation handler method with exactly one parameter typed as anything other than ElicitRequest (e.g. a String, Map, or a custom request DTO), e.g. @McpElicitation public ElicitResult handle(MyRequest req).","commonSituations":"Developers assume the framework deserializes the client's elicitation payload into a custom POJO parameter (that multi-parameter support is a TODO and not implemented), or they copy an MCP tool callback signature where typed arguments are supported.","solutions":["Change the single method parameter to io.modelcontextprotocol.spec.McpSchema.ElicitRequest","Access elicited values via request.params() (the Map) instead of declaring a custom parameter type","If you declared zero parameters, add the single ElicitRequest parameter (though zero-parameter paths take the else branch differently, ensure length==1)","Check the library version for any newer support of structured/custom elicitation parameter types before attempting workarounds"],"exampleFix":"// before\n@McpElicitation\npublic ElicitResult confirm(ConfirmRequest request) { ... }\n\n// after\n@McpElicitation\npublic ElicitResult confirm(ElicitRequest request) {\n    Object value = request.params() != null ? request.params().get(\"confirm\") : null;\n    ...\n}","handlingStrategy":"validation","validationCode":"if (m.getParameterCount() == 1 && !ElicitRequest.class.isAssignableFrom(m.getParameterTypes()[0])) {\n    throw new IllegalArgumentException(\"Handler must take a single ElicitRequest: \" + m);\n}","typeGuard":"boolean isValidElicitationMethod(Method m) {\n    return m.getParameterCount() == 1\n        && ElicitRequest.class.isAssignableFrom(m.getParameterTypes()[0]);\n}","tryCatchPattern":null,"preventionTips":["Always declare exactly one ElicitRequest parameter on @McpElicitation methods","Extract elicited values from request.params() inside the method body","Write a unit test that registers each handler and asserts registration succeeds"],"tags":["java","mcp","elicitation","method-signature","illegal-argument"],"backgroundTag":"invalid-argument-value","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}