elastic/elasticsearch · error · ClassCastException

Cannot apply [<<] operation to type [double]

Error message

Cannot apply [<<] operation to type [double]

What it means

Thrown by DefMath.lsh(double, long) which unconditionally throws. When the left operand is statically typed double, the compiler's promote() method yields double.class for the left side, selecting the lsh(double, long) overload. Left-shift is only defined for integral types; the double overload always fails.

Source

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

    }

    // shift operators, valid for any integral types, but does not promote.
    // we implement all shifts as long shifts, because the extra bits are ignored anyway.

    private static int lsh(int a, long b) {
        return a << b;
    }

    private static long lsh(long a, long b) {
        return a << b;
    }

    private static float lsh(float a, long b) {
        throw new ClassCastException("Cannot apply [<<] operation to type [float]");
    }

    private static double lsh(double a, long b) {
        throw new ClassCastException("Cannot apply [<<] operation to type [double]");
    }

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

    public static Object lsh(Object left, long right) {
        if (left instanceof Long) {
            return (long) (left) << right;
        } else {
            return intIntegralValue(left) << right;
        }
    }

    private static int rsh(int a, long b) {
        return a >> b;
    }

View on GitHub (pinned to db6a809a66)

Solutions

  1. Cast the double left operand to long before shifting: long lv = (long) v; long result = lv << shift;
  2. Change the field mapping to a long integer type if bit-shifting is the intended use case
  3. Use multiplication (v * Math.pow(2, shift)) if the goal is scaling rather than bit manipulation

Example fix

// before
double val = doc['encoded'].value;
double shifted = val << 4;

// after
long val = (long) doc['encoded'].value;
long shifted = val << 4;
Defensive patterns

Strategy: type-guard

Validate before calling

// Before left-shift on double, cast to long
double val = doc['encoded'].value;
long lv = (long) val;
return lv << 4;

Type guard

// Check that the left operand is integral before shift
boolean isShiftable(Object v) {
  return v instanceof Integer || v instanceof Long || 
         v instanceof Short || v instanceof Byte;
}

Prevention

When it happens

Trigger: A Painless script applies the << operator where the left operand is statically typed as double. The shift amount (right operand) is promoted to long. The compiler selects lsh(double, long) which unconditionally throws.

Common situations: Bit-shift on a double-typed field or scaled_float mapping; double variable used in shift encoding/packing logic; refactoring integer shift code to operate on double fields; double-typed runtime field in bit-manipulation logic.

Related errors


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