OpenFeign/feign · error · IllegalArgumentException
an expression is required.
Error message
an expression is required.
What it means
Expressions.create() builds a URI-template expression from a braced token like {param}. After stripping the braces, if nothing remains (input was '{}', '{', '}' or empty), the input is not a valid expression and this IllegalArgumentException is thrown.
Solutions
- Fix the template string to remove empty or malformed brace tokens (use a real variable name inside the braces)
- Validate templates before passing them to Feign: check for '{}' or unmatched braces
- Sanitize dynamically generated URI segments so optional/empty values drop the whole segment including braces
- Catch IllegalArgumentException from Feign.builder().target(...)/template building to surface the bad template to the caller
Example fix
// before
String path = "/users/{}"; // empty expression braces
Feign.builder().target(Api.class, baseUrl); // throws at expansion
// after
String path = "/users/{userId}"; // named expression
// or drop the segment when the value is absent:
String resolved = userId == null ? "/users" : "/users/{userId}"; Defensive patterns
Strategy: validation
Validate before calling
boolean validTemplate(String t) {
return t != null && !t.contains("{}") && !t.matches(".*\{\s*}.*")
&& t.chars().filter(c -> c == '{').count() == t.chars().filter(c -> c == '}').count();
} Try / catch
try {
Feign.builder().target(Api.class, baseUrl);
} catch (IllegalArgumentException e) {
if ("an expression is required.".equals(e.getMessage())) {
throw new IllegalStateException("template contains an empty brace expression", e);
}
throw e;
} Prevention
- Review URI templates for stray or empty braces
- Drop whole path/query segments (including braces) when a value is optional and absent
- Validate dynamically generated templates before building the client
- Use named constants for templates instead of string concatenation
When it happens
Trigger: Expanding or parsing a request template containing empty or brace-only tokens — e.g., a URI/path/query template containing '{}' or an unbalanced '{' or '}', or a template variable whose value/text resolves to empty braces.
Common situations: Typos in URI templates (stray braces); dynamically built template strings where a variable name was empty; concatenating path segments where an optional segment evaluated to nothing but left braces behind.
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
- a value is required.
- template is required.
- Status Code [ ] has already been declared to throw [ ] and…
- Cannot generate exception - check constructor parameter…
- Too many constructors marked with @FeignExceptionConstructor
AI-assisted analysis of OpenFeign/feign@e2a1e27560 (2026-09-10).
Data as JSON: /api/errors/fe2a0d1d0d4fddeb.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/feign/template/Expressions.java:81
* A pattern for matching possible variable names.
*
* <p>This pattern accepts characters allowed in RFC 6570 Section 2.3 It also allows the
* characters feign has allowed in the past "[]-$"
*
* <p>The RFC specifies that a variable name followed by a ':' should be a max-length
* specification. Feign deviates from the rfc in that the ':' value modifier is used to mark a
* regular expression.
*/
private static final Pattern VARIABLE_LIST_PATTERN =
Pattern.compile(
"(([\\w-\\[\\]$]|%[0-9A-Fa-f]{2})(\\.?([\\w-\\[\\]$]|%[0-9A-Fa-f]{2}))*(:.*|\\*)?)(,(([\\w-\\[\\]$]|%[0-9A-Fa-f]{2})(\\.?([\\w-\\[\\]$]|%[0-9A-Fa-f]{2}))*(:.*|\\*)?))*");
public static Expression create(final String value) {
/* remove the start and end braces */
final String expression = stripBraces(value);
if (expression == null || expression.isEmpty()) {
throw new IllegalArgumentException("an expression is required.");
}
/*
* Check if the expression is too long. The limit is configurable through the
* "feign.template.expression.maxLength" system property and can be disabled by setting it to a
* non-positive value.
*/
final int maxExpressionLength =
Integer.getInteger(MAX_EXPRESSION_LENGTH_PROPERTY, DEFAULT_MAX_EXPRESSION_LENGTH);
if (maxExpressionLength > 0 && expression.length() > maxExpressionLength) {
throw new IllegalArgumentException(
"expression is too long. Max length: " + maxExpressionLength);
}
/* create a new regular expression matcher for the expression */
String variableName = null;
String variablePattern = null;
String operator = null;View on GitHub (pinned to e2a1e27560)