elastic/elasticsearch · error · ClassCastException

Cannot apply [%] operation to types [{}] and [{}].

Error message

Cannot apply [%] operation to types [{}] and [{}].

What it means

DefMath.rem(Object, Object) handles the remainder operator on def values for Number and Character combinations. If neither operand matches any supported branch, the method throws a ClassCastException naming both operands' actual runtime types.

Source

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

                }
            }
        } else if (left instanceof Character) {
            if (right instanceof Number) {
                if (right instanceof Double) {
                    return (char) left % ((Number) right).doubleValue();
                } else if (right instanceof Long) {
                    return (char) left % ((Number) right).longValue();
                } else if (right instanceof Float) {
                    return (char) left % ((Number) right).floatValue();
                } else {
                    return (char) left % ((Number) right).intValue();
                }
            } else if (right instanceof Character) {
                return (char) left % (char) right;
            }
        }

        throw new ClassCastException(
            "Cannot apply [%] operation to types "
                + "["
                + left.getClass().getCanonicalName()
                + "] and ["
                + right.getClass().getCanonicalName()
                + "]."
        );
    }

    // addition: applicable to all numeric types.
    // additionally, if either type is a string, the other type can be any arbitrary type (including null)

    private static int add(int a, int b) {
        return a + b;
    }

    private static long add(long a, long b) {
        return a + b;

View on GitHub (pinned to db6a809a66)

Solutions

  1. Cast both operands to compatible numeric types: `def z = (int) x % (int) y;`
  2. Guard with instanceof to verify both are Number or Character.
  3. Use explicit types instead of def for arithmetic variables.

Example fix

// before
def n = doc['count'].value;
def m = doc['bucket'].value;
def r = n % m;

// after
def n = doc['count'].value;
def m = doc['bucket'].value;
if (n instanceof Number && m instanceof Number) {
    def r = (int) n % (int) m;
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Painless: verify both operands are Number or Character 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 modulo-compatible types
def canMod(def a, def b) {
    return (a instanceof Number && b instanceof Number) || (a instanceof Number && b instanceof Character) || (a instanceof Character && b instanceof Number) || (a instanceof Character && b instanceof Character);
}

Prevention

When it happens

Trigger: A Painless script applies % to two def variables whose runtime types are incompatible with the remainder operation. Example: `def x = 'hello'; def y = 3; def z = x % y;` where x is a String.

Common situations: Applying modulo to a def value that resolved to a String from a text or keyword field. Processing fields with heterogeneous types across documents.

Related errors


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