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

  1. Fix the template string to remove empty or malformed brace tokens (use a real variable name inside the braces)
  2. Validate templates before passing them to Feign: check for '{}' or unmatched braces
  3. Sanitize dynamically generated URI segments so optional/empty values drop the whole segment including braces
  4. 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

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


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)