{"record":{"id":"5e9ff33fd470a132","repo":"spring-projects/spring-ai","slug":"method-cannot-have-more-than-one-map-parameter-m","errorCode":null,"errorMessage":"Method cannot have more than one Map parameter: {method.getName()} in {method.getDeclaringClass().getName()}","messagePattern":"Method cannot have more than one Map parameter: (.+?) in (.+?)","errorType":"validation","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/prompt/AbstractMcpPromptMethodCallback.java","lineNumber":187,"sourceCode":"\t\t\t\thasRequestContextParam = true;\n\t\t\t}\n\t\t\telse if (isSupportedExchangeOrContextType(paramType)) {\n\t\t\t\tif (hasExchangeParam) {\n\t\t\t\t\tthrow new IllegalArgumentException(\"Method cannot have more than one exchange parameter: \"\n\t\t\t\t\t\t\t+ method.getName() + \" in \" + method.getDeclaringClass().getName());\n\t\t\t\t}\n\t\t\t\thasExchangeParam = true;\n\t\t\t}\n\t\t\telse if (GetPromptRequest.class.isAssignableFrom(paramType)) {\n\t\t\t\tif (hasRequestParam) {\n\t\t\t\t\tthrow new IllegalArgumentException(\"Method cannot have more than one GetPromptRequest parameter: \"\n\t\t\t\t\t\t\t+ method.getName() + \" in \" + method.getDeclaringClass().getName());\n\t\t\t\t}\n\t\t\t\thasRequestParam = true;\n\t\t\t}\n\t\t\telse if (Map.class.isAssignableFrom(paramType)) {\n\t\t\t\tif (hasMapParam) {\n\t\t\t\t\tthrow new IllegalArgumentException(\"Method cannot have more than one Map parameter: \"\n\t\t\t\t\t\t\t+ method.getName() + \" in \" + method.getDeclaringClass().getName());\n\t\t\t\t}\n\t\t\t\thasMapParam = true;\n\t\t\t}\n\t\t\t// Other parameter types are assumed to be individual arguments\n\t\t}\n\t}\n\n\tprotected abstract Object assignExchangeType(Class<?> paramType, Object exchange);\n\n\t/**\n\t * Builds the arguments array for invoking the method.\n\t * <p>\n\t * This method constructs an array of arguments based on the method's parameter types\n\t * and the available values (exchange, request, arguments).\n\t * @param method The method to build arguments for\n\t * @param exchange The server exchange\n\t * @param request The prompt request","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/prompt/AbstractMcpPromptMethodCallback.java#L169-L205","documentation":"A prompt method may declare at most one Map parameter (used to receive all prompt arguments). AbstractMcpPromptMethodCallback.validateParameters throws this IllegalArgumentException when a second Map-assignable parameter is found during callback registration. The framework cannot know which map should receive the arguments map.","triggerScenarios":"Registering a method like `myPrompt(Map<String,Object> args, Map<String,String> options)` — any two parameters assignable to java.util.Map trigger it, since the check is `Map.class.isAssignableFrom(paramType)` with hasMapParam already true.","commonSituations":"Adding an options/metadata Map to an existing arguments Map; generic utility methods that take multiple Map parameters being adapted into prompt handlers; type erasure makes both Map<K,V> variants look identical to the check.","solutions":["Keep only one Map parameter; consolidate options into the single arguments Map.","Replace the extra Map with individually annotated @McpArg parameters so the framework binds them by name from request.arguments().","Wrap secondary map data in a custom POJO and bind it from a single @McpArg value if the framework supports it."],"exampleFix":"// before\n@McpPrompt(name = \"search\")\npublic List<String> search(Map<String, Object> args, Map<String, String> filters) { ... }\n// after\n@McpPrompt(name = \"search\")\npublic List<String> search(Map<String, Object> args) { ... }","handlingStrategy":"validation","validationCode":"long mapParams = Arrays.stream(method.getParameters())\n    .map(Parameter::getType)\n    .filter(Map.class::isAssignableFrom)\n    .count();\nif (mapParams > 1) throw new IllegalStateException(method + \" declares multiple Map parameters\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["One Map parameter max — it receives request.arguments().","Model extra options as @McpArg-annotated individual parameters.","Due to type erasure, treat all Map<..., ...> signatures as the same kind."],"tags":["mcp","method-signature","duplicate-parameter","map-parameter"],"backgroundTag":"invalid-argument","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"}