{"record":{"id":"dbcb4d14a9803230","repo":"spring-projects/spring-ai","slug":"method-cannot-have-more-than-one-readresourcereque","errorCode":null,"errorMessage":"Method cannot have more than one ReadResourceRequest or String parameter: ${method} in ${declaringClass}","messagePattern":"Method cannot have more than one ReadResourceRequest or String parameter: (.+?) in (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/resource/AbstractMcpResourceMethodCallback.java","lineNumber":251,"sourceCode":"\t\t\t}\n\t\t\telse if (McpMeta.class.isAssignableFrom(paramType)) {\n\t\t\t\tif (hasMetaParam) {\n\t\t\t\t\tthrow new IllegalArgumentException(\"Method cannot have more than one McpMeta parameter: \"\n\t\t\t\t\t\t\t+ method.getName() + \" in \" + method.getDeclaringClass().getName());\n\t\t\t\t}\n\t\t\t\thasMetaParam = true;\n\t\t\t}\n\t\t\telse if (isExchangeOrContextType(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 (ReadResourceRequest.class.isAssignableFrom(paramType)\n\t\t\t\t\t|| String.class.isAssignableFrom(paramType)) {\n\t\t\t\tif (hasRequestOrUriParam) {\n\t\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\t\t\"Method cannot have more than one ReadResourceRequest or String parameter: \"\n\t\t\t\t\t\t\t\t\t+ method.getName() + \" in \" + method.getDeclaringClass().getName());\n\t\t\t\t}\n\t\t\t\thasRequestOrUriParam = true;\n\t\t\t\thasValidParams = true;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\t\"Method parameters must be exchange, ReadResourceRequest, String, McpMeta, or @McpProgressToken when no URI variables are present: \"\n\t\t\t\t\t\t\t\t+ method.getName() + \" in \" + method.getDeclaringClass().getName()\n\t\t\t\t\t\t\t\t+ \" has parameter of type \" + paramType.getName());\n\t\t\t}\n\t\t}\n\n\t\tif (!hasValidParams && nonSpecialParamCount > 0) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"Method must have either ReadResourceRequest or String parameter when no URI variables are present: \"\n\t\t\t\t\t\t\t+ method.getName() + \" in \" + method.getDeclaringClass().getName());","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/resource/AbstractMcpResourceMethodCallback.java#L233-L269","documentation":"Thrown when a resource method with no URI variables declares more than one parameter of type ReadResourceRequest or String. Only one parameter receives the read request (or the URI string), so a second one is ambiguous and rejected during validation.","triggerScenarios":"A @McpResource method (no URI variables) has two ReadResourceRequest and/or String parameters (e.g. ReadResourceRequest + String, or two Strings); triggered when hasRequestOrUriParam is already true.","commonSituations":"Adding a String uri parameter to a method that already takes ReadResourceRequest; leaving a second String param from a refactored signature; copy-paste duplication.","solutions":["Keep exactly one ReadResourceRequest or String parameter and remove the other","If you need the raw URI and the request object, extract the URI from the ReadResourceRequest instead of a second parameter"],"exampleFix":"// before\npublic String read(ReadResourceRequest req, String uri) { ... }\n// after\npublic String read(ReadResourceRequest req) { return req.uri(); ... }","handlingStrategy":"validation","validationCode":"long reqCount = Arrays.stream(method.getParameterTypes())\n    .filter(t -> ReadResourceRequest.class.isAssignableFrom(t) || String.class.isAssignableFrom(t))\n    .count();\nif (reqCount > 1) throw new IllegalStateException(method + \" declares \" + reqCount + \" request/URI parameters\");","typeGuard":null,"tryCatchPattern":"try { provider.build(...); }\ncatch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"more than one ReadResourceRequest or String parameter\")) { /* keep one request param */ }\n  else throw e;\n}","preventionTips":["Choose either ReadResourceRequest or String for the resource payload, not both","Extract URI details from ReadResourceRequest instead of adding a second String parameter"],"tags":["mcp","spring-ai","duplicate-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-14T11:17:12.474Z"}