elastic/elasticsearch · error · ClassCastException

Cannot apply not [~] to type [double]

Error message

Cannot apply not [~] to type [double]

What it means

The bitwise NOT operator (~) is only defined for integral types. When DefMath receives a def operand whose runtime type is Double, the double overload throws a ClassCastException immediately because bitwise complement has no defined result on IEEE 754 double-precision values.

Source

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

@SuppressWarnings("unused")
public class DefMath {

    // Unary not: only applicable to integral types

    private static int not(int v) {
        return ~v;
    }

    private static long not(long v) {
        return ~v;
    }

    private static float not(float v) {
        throw new ClassCastException("Cannot apply not [~] to type [float]");
    }

    private static double not(double v) {
        throw new ClassCastException("Cannot apply not [~] to type [double]");
    }

    private static boolean not(boolean v) {
        throw new ClassCastException("Cannot apply not [~] to type [boolean]");
    }

    private static Object not(Object unary) {
        if (unary instanceof Long) {
            return ~(Long) unary;
        } else if (unary instanceof Integer) {
            return ~(Integer) unary;
        } else if (unary instanceof Short) {
            return ~(Short) unary;
        } else if (unary instanceof Character) {
            return ~(Character) unary;
        } else if (unary instanceof Byte) {
            return ~(Byte) unary;
        }

View on GitHub (pinned to db6a809a66)

Solutions

  1. Cast the operand to an integral type: `def y = ~(long) x;`
  2. Declare the variable as int or long instead of def.
  3. Guard with instanceof to branch on integral vs floating types.

Example fix

// before
def x = doc['ratio'].value;
def y = ~x;

// after
def x = (long) doc['ratio'].value;
def y = ~x;
Defensive patterns

Strategy: type-guard

Validate before calling

// Painless: cast to long before applying ~ on a double-derived value
def x = doc['value'].value;
if (x instanceof Double) {
    def y = ~(long) x;
} else if (x instanceof Long || x instanceof Integer) {
    def y = ~x;
}

Type guard

// Painless type guard for integral types
def isIntegral(def value) {
    return value instanceof Integer || value instanceof Long || value instanceof Short || value instanceof Byte || value instanceof Character;
}

Prevention

When it happens

Trigger: A Painless script applies ~ to a def variable holding a Double at runtime. Example: `def x = 3.14; def y = ~x;`

Common situations: Applying bitwise NOT to a computed or document-derived floating-point value. Default numeric literals in Painless def mode resolving to Double when mixed with fractional values.

Related errors


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