elastic/elasticsearch · error · ClassCastException

Cannot apply [%] operation to type [boolean]

Error message

Cannot apply [%] operation to type [boolean]

What it means

The remainder operator (%) is defined for all numeric types but not for boolean. DefMath's boolean overload for rem() throws a ClassCastException when one or both def operands resolve to Boolean.

Source

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

    private static int rem(int a, int b) {
        return a % b;
    }

    private static long rem(long a, long b) {
        return a % b;
    }

    private static float rem(float a, float b) {
        return a % b;
    }

    private static double rem(double a, double b) {
        return a % b;
    }

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

    private static Object rem(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. Ensure both operands are numeric before applying %.
  2. Use an explicit integer type declaration instead of def.
  3. Guard with instanceof and branch to handle non-numeric cases.

Example fix

// before
def x = doc['flag'].value;
def m = doc['modulus'].value;
def z = x % m;

// after
def x = doc['flag'].value;
def m = doc['modulus'].value;
if (x instanceof Number && m instanceof Number) {
    def z = (int) x % (int) m;
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Painless: verify both operands are numeric before modulo
def a = doc['val1'].value;
def b = doc['val2'].value;
if (a instanceof Number && b instanceof Number) {
    def result = (int) a % (int) b;
}

Type guard

// Painless type guard for numeric operands
def bothNumeric(def a, def b) {
    return a instanceof Number && b instanceof Number;
}

Prevention

When it happens

Trigger: A Painless script applies the % operator to def variables where at least one resolves to Boolean. Example: `def x = true; def y = 3; def z = x % y;`

Common situations: A boolean field value is mistakenly used in a modulo expression. Mixing def-typed logical and numeric values in the same arithmetic expression.

Related errors


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