quarkusio/quarkus · error · IllegalArgumentException
Illegal end of expression
Error message
Illegal end of expression
What it means
The parser rejects a '$' at the very end of a ClientHeaderParam value because ${ requires a property name and a closing brace; a trailing '$' can never form a valid expression. It fails fast at build time with IllegalArgumentException wrapped with the offending input.
Source
Thrown at extensions/resteasy-reactive/rest-client/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/MicroProfileRestClientEnricher.java:1179
this.input = Objects.requireNonNull(input);
this.sourceMethod = sourceMethod;
}
// this is a pretty naive implementation, but it suffices for what we are trying to do
List<Node> parse() {
int i = 0;
int configStart = -1;
int accessibleStart = -1;
int verbatimStart = -1;
List<Node> nodes = new ArrayList<>();
while (i < input.length()) {
char c = input.charAt(i);
if (c == '$') {
if ((configStart != -1) || (accessibleStart != -1)) {
throw new IllegalArgumentException(createEffectiveErrorMessage("Cannot mix expressions"));
}
if (i == input.length() - 1) {
throw new IllegalArgumentException(createEffectiveErrorMessage("Illegal end of expression"));
}
if (input.charAt(i + 1) != '{') {
throw new IllegalArgumentException(createEffectiveErrorMessage("'$' must always be followed by '{'"));
}
if (verbatimStart != -1) {
nodes.add(new Verbatim(input.substring(verbatimStart, i)));
}
i += 2;
configStart = i;
verbatimStart = -1;
} else if (c == '{') {
if ((configStart != -1) || (accessibleStart != -1)) {
throw new IllegalArgumentException(createEffectiveErrorMessage("Cannot mix expressions"));
}
if (i == input.length() - 1) {
throw new IllegalArgumentException(createEffectiveErrorMessage("Illegal end of expression"));
}
if (verbatimStart != -1) {View on GitHub (pinned to e1c734241f)
Solutions
- Complete the expression: replace trailing '$' with a full ${property} form
- Remove the stray '$' if it was accidental
- If a literal '$' is needed as verbatim text, ensure it is not the last character or restructure (the naive parser treats a lone '$' mid-text followed by '{' as an expression start; a trailing '$' is always invalid)
Example fix
// before @ClientHeaderParam(name="X-Price", value="100$") // after @ClientHeaderParam(name="X-Price", value="USD 100")
Defensive patterns
Strategy: validation
Validate before calling
String v = "apikey$";
if (v.trim().endsWith("$")) {
throw new IllegalArgumentException("ClientHeaderParam value cannot end with a bare '$'");
} Prevention
- Never end header values with a bare '$'
- Always complete ${...} expressions with property name and closing brace
- Avoid raw currency symbols in annotation values; compute them in provider methods
When it happens
Trigger: Annotation value ending with a dangling '$', e.g. @ClientHeaderParam(name="X", value="apikey$") — often after accidental truncation or an intended literal '$' unescaped.
Common situations: Copy-paste truncation of long header values, or attempting to embed a literal dollar sign (e.g. currency) at the end of a header value.
Related errors
- Cannot mix expressions
- '$' must always be followed by '{'
- 'quarkus-narayana-lra' can only work if 'quarkus-rest-client
- Token exchange is required but OIDC client is configured to
- Not possible to define the scope %s for the REST client %s
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/06bd714c665f9db3.
Report an issue: GitHub.