elastic/elasticsearch · error · ClassCastException

Cannot apply [<] operation to type [boolean]

Error message

Cannot apply [<] operation to type [boolean]

What it means

Thrown by DefMath.lt(boolean, boolean) which unconditionally throws. The Painless compiler's promote() method maps a (boolean, boolean) pair to boolean.class, so the less-than operator dispatches to this overload at compile time. Unlike Java which rejects this at compile time, Painless defers it to a runtime ClassCastException because the method table must include a boolean slot for every operator.

Source

Thrown at modules/lang-painless/src/main/java/org/elasticsearch/painless/DefMath.java:608

    private static boolean lt(int a, int b) {
        return a < b;
    }

    private static boolean lt(long a, long b) {
        return a < b;
    }

    private static boolean lt(float a, float b) {
        return a < b;
    }

    private static boolean lt(double a, double b) {
        return a < b;
    }

    private static boolean lt(boolean a, boolean b) {
        throw new ClassCastException("Cannot apply [<] operation to type [boolean]");
    }

    private static boolean lt(Object left, Object right) {
        if (left instanceof Number) {
            if (right instanceof Number) {
                if (left instanceof Double || right instanceof Double) {
                    return ((Number) left).doubleValue() < ((Number) right).doubleValue();
                } else if (left instanceof Float || right instanceof Float) {
                    return ((Number) left).floatValue() < ((Number) right).floatValue();
                } else if (left instanceof Long || right instanceof Long) {
                    return ((Number) left).longValue() < ((Number) right).longValue();
                } else {
                    return ((Number) left).intValue() < ((Number) right).intValue();
                }
            } else if (right instanceof Character) {
                if (left instanceof Double) {
                    return ((Number) left).doubleValue() < (char) right;
                } else if (left instanceof Long) {

View on GitHub (pinned to db6a809a66)

Solutions

  1. Replace the relational comparison with a logical operator: use == , != , or conditional logic instead of <
  2. Convert booleans to integers before comparing: int ia = a ? 1 : 0; int ib = b ? 1 : 0; then compare ia < ib
  3. Re-examine the field mapping — if ordering is needed, the field should be numeric, not boolean

Example fix

// before
boolean isActive = doc['active'].value;
boolean isVerified = doc['verified'].value;
boolean result = isActive < isVerified;

// after
int activeFlag = doc['active'].value ? 1 : 0;
int verifiedFlag = doc['verified'].value ? 1 : 0;
boolean result = activeFlag < verifiedFlag;
Defensive patterns

Strategy: type-guard

Validate before calling

// Before comparing booleans, convert to integers if ordering is needed
boolean a = doc['flag1'].value;
boolean b = doc['flag2'].value;
int ia = a ? 1 : 0;
int ib = b ? 1 : 0;
// Now safe to use relational operators
return ia < ib;

Type guard

// Check if a type supports relational comparison
boolean isRelationalComparable(Class<?> clazz) {
  return clazz == int.class || clazz == long.class || 
         clazz == float.class || clazz == double.class ||
         clazz == char.class;
}

Prevention

When it happens

Trigger: A Painless script applies the < operator to two operands that are both statically typed as boolean. The compiler resolves both to boolean.class, binary promotion yields boolean.class, and the lt(boolean, boolean) overload is selected.

Common situations: Comparing two boolean fields or flags with < instead of a logical operator; attempting to sort or rank by a boolean field; copy-pasting comparison logic from numeric code into a boolean context; runtime field mapped as boolean used in a relational comparison.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/c5e9760080fb0440. Report an issue: GitHub.