elastic/elasticsearch · error · ClassCastException

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

Error message

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

What it means

DefMath.add(Object, Object) handles binary addition for numeric types, String concatenation (either operand being String), 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:428

                }
            }
        } 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()
                + "]."
        );
    }

    private static int sub(int a, int b) {
        return a - b;
    }

    private static long sub(long a, long b) {
        return a - b;
    }

    private static float sub(float a, float b) {

View on GitHub (pinned to db6a809a66)

Solutions

  1. Cast operands to compatible types (double/long for arithmetic, String for concatenation).
  2. Guard with instanceof to verify operands are Number, String, or Character before adding.
  3. Use explicit types instead of def for arithmetic and string operations.

Example fix

// before
def a = doc['val1'].value;
def b = doc['val2'].value;
def sum = a + b;

// after
def a = doc['val1'].value;
def b = doc['val2'].value;
if (a instanceof Number && b instanceof Number) {
    def sum = (double) a + (double) b;
} else {
    def sum = String.valueOf(a) + String.valueOf(b);
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Painless: verify operands are compatible (Number/String/Character) before addition
def a = doc['val1'].value;
def b = doc['val2'].value;
if (a instanceof Number && b instanceof Number) {
    def result = (double) a + (double) b;
} else if (a instanceof String || b instanceof String) {
    def result = String.valueOf(a) + String.valueOf(b);
} else {
    // incompatible types
}

Type guard

// Painless type guard for addable types
def canAdd(def a, def b) {
    return (a instanceof String) || (b instanceof String) || (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 adds two def variables whose runtime types are incompatible with addition and neither is a String. Example: `def x = new ArrayList(); def y = 5; def z = x + y;` where x is a List (not String, not Number, not Character).

Common situations: Adding a def value that resolved to an unexpected type (List, Map, custom object) from a document field or API call. Processing values from heterogeneous sources where the runtime type is unpredictable.

Related errors


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