quarkusio/quarkus · error · IllegalStateException

Expression is not a literal:

Error message

Expression is not a literal: 

What it means

asLiteral() returns the pre-evaluated literal value of a literal expression as a CompletionStage. It throws IllegalStateException when the ExpressionImpl was not constructed as a literal (literal field is null), meaning the expression is dynamic or a part-based expression that has no cached literal value.

Source

Thrown at independent-projects/qute/core/src/main/java/io/quarkus/qute/ExpressionImpl.java:95

    @Override
    public boolean isLiteral() {
        return literal != null && parts.size() <= 1;
    }

    public CompletableFuture<Object> getLiteralValue() {
        return literal != null ? literal.toCompletableFuture() : null;
    }

    @Override
    public Object getLiteral() {
        return literal != null ? literal.get() : null;
    }

    @Override
    public CompletionStage<Object> asLiteral() {
        if (literal == null) {
            throw new IllegalStateException("Expression is not a literal: " + toString());
        }
        return literal;
    }

    public Origin getOrigin() {
        return origin;
    }

    @Override
    public int getGeneratedId() {
        return id;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + Objects.hashCode(toOriginalString());

View on GitHub (pinned to e1c734241f)

Solutions

  1. Guard with expression.isLiteral() (or check the literal field) before calling asLiteral().
  2. Fall back to evaluating the expression through the resolution context when it is not a literal.
  3. Inspect the template expression origin to confirm it was created as a literal.

Example fix

// before
Object v = expr.asLiteral().toCompletableFuture().join();
// after
if (expr.isLiteral()) {
    Object v = expr.asLiteral().toCompletableFuture().join();
} else {
    Object v = expr.eval(resolutionContext).toCompletableFuture().join();
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (expr == null || !expr.isLiteral()) {
    // not usable as literal — evaluate dynamically instead
}

Type guard

boolean isLiteralExpr(Expression e) {
    return e instanceof ExpressionImpl impl && impl.isLiteral();
}

Try / catch

try {
    return expr.asLiteral().toCompletableFuture().join();
} catch (IllegalStateException ex) {
    return expr.eval(ctx).toCompletableFuture().join(); // dynamic fallback
}

Prevention

When it happens

Trigger: Calling asLiteral() on an expression created via parts (e.g. from a normal template expression like {name}) rather than via literal()/literalFrom().

Common situations: Extension or custom resolver code that assumes an expression is a constant and calls asLiteral() on user-supplied template expressions that turn out to be dynamic (contain method calls, properties, etc.).

Related errors


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