elastic/elasticsearch · error · ClassCastException

Cannot apply [<=] operation to type [boolean]

Error message

Cannot apply [<=] operation to type [boolean]

What it means

Thrown by DefMath.lte(boolean, boolean) which unconditionally throws. When both operands are statically typed boolean, the compiler's promote() method yields boolean.class and dispatches to this overload. Less-than-or-equal has no meaningful semantics for booleans, so the overload always fails.

Source

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

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

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

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

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

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

    private static boolean lte(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 <= with equality (==) or inequality (!=) for boolean operands
  2. Convert booleans to integers (0/1) before applying <= if you need ordering semantics
  3. Change the field mapping from boolean to a numeric type if ordering is a genuine requirement

Example fix

// before
boolean a = doc['enabled'].value;
boolean b = doc['locked'].value;
boolean result = a <= b;

// after
int ia = doc['enabled'].value ? 1 : 0;
int ib = doc['locked'].value ? 1 : 0;
boolean result = ia <= ib;
Defensive patterns

Strategy: type-guard

Validate before calling

// Before using <= on booleans, convert to integers
boolean a = doc['flag_a'].value;
boolean b = doc['flag_b'].value;
int ia = a ? 1 : 0;
int ib = b ? 1 : 0;
return ia <= ib;

Type guard

// Verify the value is not boolean before relational comparison
boolean isNotBoolean(Object v) {
  return !(v instanceof Boolean);
}

Prevention

When it happens

Trigger: A Painless script applies the <= operator to two operands both statically typed as boolean. Binary promotion selects boolean.class, and the lte(boolean, boolean) overload is called.

Common situations: Using <= on boolean flags or toggles; attempting range logic on a boolean field; refactoring numeric comparison code to operate on boolean fields without changing the operator; aggregating or sorting by a boolean field with <= logic.

Related errors


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