spring-projects/spring-ai · error · IllegalArgumentException
Method must have either ReadResourceRequest or String…
Error message
Method must have either ReadResourceRequest or String parameter when no URI variables are present: ${method} in ${declaringClass} What it means
Thrown when a URI-variable-less resource method has non-special parameters (excluding @McpProgressToken and McpMeta) but none of them is a ReadResourceRequest or String. The framework requires the resource payload (the read request or URI string) to be bindable, so such a signature is rejected.
Solutions
- Add a ReadResourceRequest parameter to receive the resource read request
- Or add a String parameter to receive the URI
- If the method needs no request data at all, ensure non-special parameters are removed so validation passes
Example fix
// before
@McpResource(uri = "cfg://app")
public String read(McpSyncRequestContext ctx) { ... }
// after
@McpResource(uri = "cfg://app")
public String read(ReadResourceRequest request, McpSyncRequestContext ctx) { ... } Defensive patterns
Strategy: validation
Validate before calling
boolean hasPayload = Arrays.stream(method.getParameterTypes())
.anyMatch(t -> ReadResourceRequest.class.isAssignableFrom(t) || String.class.isAssignableFrom(t));
if (!hasPayload) throw new IllegalStateException(method + " lacks a ReadResourceRequest/String parameter"); Try / catch
try { provider.build(...); }
catch (IllegalArgumentException e) {
if (e.getMessage().contains("must have either ReadResourceRequest or String parameter")) { /* add the missing request param */ }
else throw e;
} Prevention
- Always include a ReadResourceRequest or String parameter in resource handlers
- Check signatures after refactoring to ensure the payload parameter was not dropped
When it happens
Trigger: A @McpResource method with no URI variables whose parameters are only context/exchange/McpMeta types (hasValidParams stays false while nonSpecialParamCount > 0).
Common situations: Writing a resource handler that takes only a context, forgetting the request/URI parameter; deleting the String parameter during a refactor while keeping others.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Method parameters must be exchange, ReadResourceRequest…
- Async complete methods should use McpAsyncRequestContext…
- Async complete methods should use McpAsyncRequestContext…
- ASYNC Providers don't support imperative (non-reactive)…
- Method cannot have more than one CompleteArgument parameter
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/0f445674429cf9c7.
Report an issue: GitHub.
Appendix: source
Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/resource/AbstractMcpResourceMethodCallback.java:267
|| String.class.isAssignableFrom(paramType)) {
if (hasRequestOrUriParam) {
throw new IllegalArgumentException(
"Method cannot have more than one ReadResourceRequest or String parameter: "
+ method.getName() + " in " + method.getDeclaringClass().getName());
}
hasRequestOrUriParam = true;
hasValidParams = true;
}
else {
throw new IllegalArgumentException(
"Method parameters must be exchange, ReadResourceRequest, String, McpMeta, or @McpProgressToken when no URI variables are present: "
+ method.getName() + " in " + method.getDeclaringClass().getName()
+ " has parameter of type " + paramType.getName());
}
}
if (!hasValidParams && nonSpecialParamCount > 0) {
throw new IllegalArgumentException(
"Method must have either ReadResourceRequest or String parameter when no URI variables are present: "
+ method.getName() + " in " + method.getDeclaringClass().getName());
}
}
protected void validateParamType(Class<?> paramType) {
}
/**
* Validates method parameters when URI variables are present. This method provides
* common validation logic and delegates exchange type checking to subclasses.
* @param method The method to validate
* @throws IllegalArgumentException if the parameters are not compatible
*/
protected void validateParametersWithUriVariables(Method method) {
Parameter[] parameters = method.getParameters();
// Count special parameters (exchange, request, progress token, and meta)View on GitHub (pinned to 98a7beda4f)