quarkusio/quarkus · error · IllegalArgumentException

Invalid expression: ${expression}

Error message

Invalid expression: ${expression}

What it means

ConfigUtils.interpolate resolves MicroProfile config property placeholders of the form ${name} inside REST client values (URLs, URIs, proxies). This error is thrown when the expression contains ${ without a matching closing }, so the library cannot determine the property name. It is a syntax validation of the interpolated string.

Source

Thrown at extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/ConfigUtils.java:29

    static final String PREFIX = "${";
    static final String SUFFIX = "}";

    /**
     * Interpolates the given expression. The expression is expected to be in the form of ${config.property.name}.
     *
     * @param expression the expression to interpolate
     * @param required whether the expression is required to be present in the configuration
     * @return null if the resulting expression is empty, otherwise the interpolated expression
     */
    @SuppressWarnings("unused")
    public static String interpolate(String expression, boolean required) {
        StringBuilder sb = new StringBuilder(expression);
        int idx;
        while ((idx = sb.lastIndexOf(PREFIX)) > -1) {
            int endIdx = sb.indexOf(SUFFIX, idx);
            if (endIdx < 0) {
                throw new IllegalArgumentException("Invalid expression: " + expression);
            }
            String configValue = getConfigValue(sb.substring(idx, endIdx + 1), required);
            // If no value is found, we return null directly
            if (configValue == null) {
                return null;
            }
            sb.replace(idx, endIdx + 1, configValue);
        }
        if (sb.length() == 0) {
            return null;
        }
        return sb.toString();
    }

    /**
     * Obtains the value of the {@param configProperty} expression. This expressions MUST be in the form of ${...}
     */
    public static String getConfigValue(String configProperty, boolean required) {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Add the missing closing brace '}' to the property reference
  2. Escape or remove the stray '${' if no config substitution is intended
  3. Verify the resolved value at build time by logging the raw property from application.properties

Example fix

# before
quarkus.rest-client.svc.url=${API_HOST/api
# after
quarkus.rest-client.svc.url=${API_HOST}:8080/api
Defensive patterns

Strategy: validation

Validate before calling

static void validateInterpolation(String expr) {
    int open = 0;
    for (int i = 0; i < expr.length(); i++) {
        char c = expr.charAt(i);
        if (c == '$' && i + 1 < expr.length() && expr.charAt(i + 1) == '{') open++;
        else if (c == '}') open--;
        if (open < 0) throw new IllegalArgumentException("Unmatched } in: " + expr);
    }
    if (open != 0) throw new IllegalArgumentException("Unclosed ${ in: " + expr);
}

Try / catch

try {
    String url = ConfigUtils.interpolate(rawUrl, true);
} catch (IllegalArgumentException e) {
    throw new ConfigurationException("Malformed ${} expression in rest-client config: " + rawUrl, e);
}

Prevention

When it happens

Trigger: Passing a value to a rest client builder (e.g. baseUri/url/proxy config from application.properties or @RegisterRestClient config) that contains '${' with no '}' closing brace, such as a truncated or typo'd property reference.

Common situations: Typo in application.properties like quarkus.rest-client.myservice.url=${MY_URL; accidentally truncated string interpolation in code generation; shell/env placeholder copied verbatim without a closing brace.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/4a5a904f8e726945. Report an issue: GitHub.