quarkusio/quarkus · error · TemplateException

Not a binary operator:

Error message

Not a binary operator: 

What it means

In IfSectionHelper, the internal BooleanRepresentation switch handles logical binary operators; if the stored operator code is not one of the known operators, evaluate() throws TemplateException("Not a binary operator: " + this). This signals an internal inconsistency: the parser produced an operator the evaluator does not recognize, or the helper state was corrupted.

Source

Thrown at independent-projects/qute/core/src/main/java/io/quarkus/qute/IfSectionHelper.java:492

            return precedence;
        }

        boolean evaluate(Object op1, Object op2) {
            switch (this) {
                case EQ:
                    return equals(op1, op2);
                case NE:
                    return !equals(op1, op2);
                case GE:
                case GT:
                case LE:
                case LT:
                    return compare(op1, op2);
                case AND:
                case OR:
                    return !isFalsy(op2);
                default:
                    throw new TemplateException("Not a binary operator: " + this);
            }
        }

        boolean equals(Object op1, Object op2) {
            if (Objects.equals(op1, op2)) {
                return true;
            }
            if (op1 != null && op2 != null && (op1 instanceof Number || op2 instanceof Number)) {
                // Both operands are not null and at least one of them is a number
                return getDecimal(op1).compareTo(getDecimal(op2)) == 0;
            }
            return false;
        }

        @SuppressWarnings({ "rawtypes", "unchecked" })
        boolean compare(Object op1, Object op2) {
            if (op1 == null || op2 == null) {
                throw new TemplateException("Unable to compare null operands [op1=" + op1 + ", op2=" + op2 + "]");

View on GitHub (pinned to e1c734241f)

Solutions

  1. Verify the template's {#if} expression uses supported operators (&&, ||, comparison) and no stray characters.
  2. Upgrade/align Quarkus and Qute versions so parser and evaluator agree on operator codes.
  3. Report it as a bug if a plain supported expression triggers it — it indicates an internal parser/evaluator mismatch.

Example fix

// before
{#if a ??? b} // unsupported/misparsed operator
// after
{#if a ?: b} // use the supported elvis operator
Defensive patterns

Strategy: try-catch

Validate before calling

// validate operator syntax ahead of time
if (!SUPPORTED_OPERATORS.contains(opToken)) {
    throw new IllegalArgumentException("unsupported operator: " + opToken);
}

Type guard

boolean isKnownBinaryOp(IfSectionHelper.BooleanRepresentation op) {
    return op == AND || op == OR; // extend per known set
}

Try / catch

try {
    return condition.evaluate(ctx);
} catch (TemplateException ex) {
    if (ex.getMessage().startsWith("Not a binary operator")) {
        throw new IllegalArgumentException("Malformed {#if} expression — check template syntax/versions", ex);
    }
    throw ex;
}

Prevention

When it happens

Trigger: Reaching the default branch of the operator switch during {#if} evaluation — an unrecognized/comparator operator leaked into the boolean-operator path, typically due to an internal bug, malformed custom operator registration, or version mismatch.

Common situations: Custom operator extensions or forks of Qute; template syntax accepted by one Qute version but not the evaluator of another after an upgrade; corrupted cached template state.

Related errors


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