OpenFeign/feign · error · IllegalArgumentException
Value does not match the expression pattern
Error message
Value {expanded} does not match the expression pattern: {pattern} What it means
After expanding a template expression variable, Feign validates the resulting value against the variable's declared pattern (the 'name:pattern' syntax inside the expression, e.g. {id:\d+}). If the expanded value does not match that pattern, the expansion is rejected with this IllegalArgumentException. This guards against producing invalid URIs when a constrained variable receives a non-conforming value.
Solutions
- Fix the value passed to the variable so it conforms to the declared pattern.
- Loosen or correct the pattern in the template/annotation (e.g. {id:.+} for permissive matching).
- Pre-validate the value in client code against the same pattern before expanding.
- Remove the pattern constraint entirely ({id} instead of {id:\d+}) if no constraint is needed.
Example fix
// before
@RequestLine("GET /users/{id:\\d+}")
User get(String id); // called with get("abc") -> pattern mismatch
// after
@RequestLine("GET /users/{id}")
User get(String id); // or pass a numeric id Defensive patterns
Strategy: validation
Validate before calling
Pattern p = Pattern.compile("\\d+");
if (userId == null || !p.matcher(userId).matches()) {
throw new IllegalArgumentException("userId must match the declared template pattern");
} Try / catch
try {
return feignClient.get(userId);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("does not match the expression pattern")) {
throw new InvalidUserIdException(userId, e);
}
throw e;
} Prevention
- Keep template patterns in sync with the actual data format of the variables.
- Pre-validate values against the same regex used in the template before calling the client.
- Prefer unconstrained expressions ({id}) unless a constraint is genuinely needed.
- Watch for encoded values that change the string so it no longer matches the pattern.
When it happens
Trigger: Declaring an expression with a regex constraint like {userId:[0-9]+} and calling resolve/expand with a value that fails the regex (e.g. 'abc' for [0-9]+); value contains characters the pattern excludes; iterable expansion producing a joined value that violates the pattern.
Common situations: Passing null-ish 'null' string, empty string, or URL-encoded values that no longer match the declared pattern; changing a variable's type/format upstream without updating the interface annotation; copy-pasted pattern from another endpoint no longer fitting the data.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- an expression is required.
- expression is too long. Max length
- a value is required.
- template is required.
- Status Code [ ] has already been declared to throw [ ] and…
AI-assisted analysis of OpenFeign/feign@e2a1e27560 (2026-09-10).
Data as JSON: /api/errors/c23f54d0729eb454.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/feign/template/Expressions.java:205
if (optional.isPresent()) {
expanded.append(this.expand(optional.get(), encode));
} else {
if (!this.nameRequired) {
return null;
}
expanded.append(this.encode(this.getName())).append("=");
}
} else {
if (this.nameRequired) {
expanded.append(this.encode(this.getName())).append("=");
}
expanded.append((encode) ? encode(variable) : variable);
}
/* return the string value of the variable */
String result = expanded.toString();
if (!this.matches(result)) {
throw new IllegalArgumentException(
"Value " + expanded + " does not match the expression pattern: " + this.getPattern());
}
return result;
}
protected String expandIterable(Iterable<?> values) {
StringBuilder result = new StringBuilder();
for (Object value : values) {
if (value == null) {
/* skip */
continue;
}
/* expand the value */
String expanded = this.encode(value);
if (expanded.isEmpty()) {
/* always append the separator */
result.append(this.separator);View on GitHub (pinned to e2a1e27560)