elastic/elasticsearch · error · ClassCastException

Cannot apply [-] operation to type [{}].

Error message

Cannot apply [-] operation to type [{}].

What it means

DefMath.neg(Object) is the catch-all for unary negation on def values. It handles boxed numeric types (Double, Long, Integer, Float, Short, Character, Byte). If the runtime type matches none of these (e.g., BigInteger, BigDecimal, String), the method throws a ClassCastException naming the actual type.

Source

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

    private static Object neg(final Object unary) {
        if (unary instanceof Double) {
            return -(double) unary;
        } else if (unary instanceof Long) {
            return -(long) unary;
        } else if (unary instanceof Integer) {
            return -(int) unary;
        } else if (unary instanceof Float) {
            return -(float) unary;
        } else if (unary instanceof Short) {
            return -(short) unary;
        } else if (unary instanceof Character) {
            return -(char) unary;
        } else if (unary instanceof Byte) {
            return -(byte) unary;
        }

        throw new ClassCastException("Cannot apply [-] operation to type " + "[" + unary.getClass().getCanonicalName() + "].");
    }

    private static int plus(int v) {
        return +v;
    }

    private static long plus(long v) {
        return +v;
    }

    private static float plus(float v) {
        return +v;
    }

    private static double plus(double v) {
        return +v;
    }

View on GitHub (pinned to db6a809a66)

Solutions

  1. Convert the value to a numeric type before negation: `def y = -(double) x;`
  2. Guard with instanceof to ensure the value is a recognized Number subtype.
  3. Use explicit types instead of def for numeric variables.

Example fix

// before
def x = doc['amount'].value;
def y = -x;

// after
def x = doc['amount'].value;
if (x instanceof Number) {
    def y = -(double) x;
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Painless: check the value is a recognized Number before negation
def x = doc['value'].value;
if (x instanceof Number) {
    def y = -(double) x;
} else {
    // handle non-numeric case
}

Type guard

// Painless type guard for supported numeric box types
def isRecognizedNumber(def value) {
    return value instanceof Double || value instanceof Long || value instanceof Integer || value instanceof Float || value instanceof Short || value instanceof Character || value instanceof Byte;
}

Prevention

When it happens

Trigger: A Painless script applies unary minus to a def variable whose runtime type is not a recognized boxed numeric type. Example: `def x = '42'; def y = -x;` where x is a String.

Common situations: Negating a def value that unexpectedly resolved to a String (from a keyword or text field). Processing values from external Java libraries that return BigInteger or BigDecimal.

Related errors


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