spring-projects/spring-ai · error · IllegalArgumentException
Failed to extract all URI variables from request URI: {uri}.
Error message
Failed to extract all URI variables from request URI: {uri}. Expected variables: {expectedVariables}, but found: {foundVariables} What it means
The request URI did not yield values for all URI template variables declared on the @McpResource method. The callback compares the extracted variable count to the declared variables and throws when they differ.
Source
Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/resource/SyncStatelessMcpResourceMethodCallback.java:118
* @param request The resource request, must not be null
* @return The resource result
* @throws McpError if there is an error invoking the resource method
* @throws IllegalArgumentException if the request is null or if URI variable
* extraction fails
*/
@Override
public ReadResourceResult apply(McpTransportContext context, ReadResourceRequest request) {
if (request == null) {
throw new IllegalArgumentException("Request must not be null");
}
try {
// Extract URI variable values from the request URI
Map<String, String> uriVariableValues = this.uriTemplateManager.extractVariableValues(request.uri());
// Verify all URI variables were extracted if URI variables are expected
if (!this.uriVariables.isEmpty() && uriVariableValues.size() != this.uriVariables.size()) {
throw new IllegalArgumentException("Failed to extract all URI variables from request URI: "
+ request.uri() + ". Expected variables: " + this.uriVariables + ", but found: "
+ uriVariableValues.keySet());
}
// Build arguments for the method call
Object[] args = this.buildArgs(this.method, context, request, uriVariableValues);
// Invoke the method
this.method.setAccessible(true);
Object result = this.method.invoke(this.bean, args);
// Convert the result to a ReadResourceResult using the converter
return this.resultConverter.convertToReadResourceResult(result, request.uri(), this.mimeType,
this.contentType, this.meta);
}
catch (Exception e) {
if (e instanceof McpError mcpError && mcpError.getJsonRpcError() != null) {
throw mcpError;View on GitHub (pinned to 98a7beda4f)
Solutions
- Send a request URI that fully matches the @McpResource uri template, filling every {variable}
- Verify the template placeholders match the method parameter names (this.uriVariables)
- Normalize/decode the request URI before it reaches the callback in custom transports
- Add integration tests that exercise the templated URI end to end
Example fix
// before
var result = client.readResource("file:///docs"); // template is file://{path}
// after
var result = client.readResource("file:///docs/report.txt"); Defensive patterns
Strategy: validation
Validate before calling
Set<String> declared = Set.of("path"); // from the @McpResource template
Map<String,String> vars = uriTemplateManager.extractVariableValues(request.uri());
if (vars.size() != declared.size()) {
throw new IllegalArgumentException("URI " + request.uri() + " does not fill all template variables");
} Type guard
boolean uriMatchesTemplate(String uri, String template) {
return uri != null && !uri.isBlank() && uri.startsWith(template.substring(0, template.indexOf('{')));
} Try / catch
try {
return callback.apply(context, request);
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("Failed to extract all URI variables")) {
return errorResult("Resource URI does not match template");
}
throw e;
} Prevention
- Test each @McpResource template with a fully filled example URI
- Keep placeholder names aligned with method parameters
- URL-decode requests before extraction in custom transports
When it happens
Trigger: A ReadResourceRequest whose URI does not match the method's URI template (e.g. missing a path segment or query part that maps to a declared {var}), so extractVariableValues returns fewer variables than declared.
Common situations: Client calling the wrong resource URI; typos in URI template placeholders; registering a template with variables the caller omits; URI-encoding differences that break extraction.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- Method must have parameters for all URI variables. Expected
- URI variable parameters must be of type String: ${method} in
- Failed to assign all URI variables to method parameters. Ass
- URI must not be null or empty
- Method must have exactly 1 parameter (List<McpSchema.Resourc
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/6931ba03c7c39c0d.
Report an issue: GitHub.