quarkusio/quarkus · error · TemplateException

Unable to compare null operands [op1=, op2=]

Error message

Unable to compare null operands [op1=, op2=]

What it means

When a {when}/{if} comparison operator (e.g. >, >=) is evaluated and either operand is null, Qute cannot order the values and throws TemplateException from compare(). Equality-style checks handle null fine, but relational comparison of null is rejected deliberately rather than returning a silently wrong result.

Source

Thrown at independent-projects/qute/core/src/main/java/io/quarkus/qute/WhenSectionHelper.java:261

                    return !Objects.equals(value, params.get(0));
                case GE:
                case GT:
                case LE:
                case LT:
                    return compare(value, params.get(0));
                case IN:
                    return params.contains(value);
                case NOT_IN:
                    return !params.contains(value);
                default:
                    throw new TemplateException("Not a legal operator: " + this);
            }
        }

        @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 + "]");
            }
            Comparable c1;
            Comparable c2;
            if (op1 instanceof Comparable && op1.getClass().equals(op2.getClass())) {
                c1 = (Comparable) op1;
                c2 = (Comparable) op2;
            } else {
                c1 = Operator.getDecimal(op1);
                c2 = Operator.getDecimal(op2);
            }
            int result = c1.compareTo(c2);
            switch (this) {
                case GE:
                    return result >= 0;
                case GT:
                    return result > 0;
                case LE:
                    return result <= 0;

View on GitHub (pinned to e1c734241f)

Solutions

  1. Guard the comparison with a null check first, e.g. {#if item.price != null && item.price > 10}.
  2. Use Qute's null-safe / default operators to coerce the operand, e.g. {item.price ?: 0} before comparing.
  3. Provide non-null defaults in the data model when building the template data.
  4. Restructure the {when} to compare only after an {#is} null check branch.

Example fix

// before
{#if order.discount > 0}...{/}
// after
{#if order.discount != null && order.discount > 0}...{/}
// or
{#if (order.discount ?: 0) > 0}...{/}
Defensive patterns

Strategy: validation

Validate before calling

// in template
{#if item.price != null && item.price > 10}...{/}
// in Java before rendering
Objects.requireNonNullElse(item.getPrice(), BigDecimal.ZERO);

Type guard

boolean isComparable(Object a, Object b) {
    return a != null && b != null && a.getClass().equals(b.getClass()) && a instanceof Comparable;
}

Try / catch

try {
    renderTemplate(tpl, data);
} catch (TemplateException e) {
    if (e.getMessage().startsWith("Unable to compare null operands")) {
        // add null guards / defaults in the template or data model
    }
}

Prevention

When it happens

Trigger: Evaluating expressions like {#when item.price > 10} or {#if a >= b} where item.price or b resolves to null (missing property, null value passed in the data map).

Common situations: Optional data not supplied to the template; properties absent on some objects in a collection; API/model changes that made a field nullable; forgetting the null-safe '?elvis' style access before comparing.

Related errors


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