elastic/elasticsearch · error · ClassCastException

Cannot cast {} to {}

Error message

Cannot cast {} to {}

What it means

DefMath.cast throws this ClassCastException at compile/link time when an explicit cast in a Painless script involves a boolean on either side. Java's explicitCastArguments would silently allow boolean<->numeric conversions in some JVM paths, but Painless deliberately forbids them: casts to or from boolean are rejected with this error. All other primitive-to-primitive casts go through explicitCastArguments normally.

Source

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

        // bind to the boxed type
        MethodHandle cast = DYNAMIC_CAST.bindTo(desired);
        return MethodHandles.filterReturnValue(target, cast);
    }

    /** Forces a cast to class A for target (only if types differ) */
    public static MethodHandle cast(Class<?> classA, MethodHandle target) {
        MethodType newType = MethodType.methodType(classA).unwrap();
        MethodType targetType = MethodType.methodType(target.type().returnType()).unwrap();

        // don't do a conversion if types are the same. explicitCastArguments has this opto,
        // but we do it explicitly, to make the boolean check simpler
        if (newType.returnType() == targetType.returnType()) {
            return target;
        }

        // we don't allow the to/from boolean conversions of explicitCastArguments
        if (newType.returnType() == boolean.class || targetType.returnType() == boolean.class) {
            throw new ClassCastException("Cannot cast " + targetType.returnType() + " to " + newType.returnType());
        }

        // null return values are not possible for our arguments.
        return MethodHandles.explicitCastArguments(target, target.type().changeReturnType(newType.returnType()));
    }
}

View on GitHub (pinned to db6a809a66)

Solutions

  1. Replace numeric-to-boolean casts with an explicit comparison: 'boolean b = (x != 0);'.
  2. Replace boolean-to-numeric casts with a ternary: 'int i = b ? 1 : 0;'.
  3. Avoid the cast entirely by restructuring the conditional logic to use the boolean directly.

Example fix

// before
int flag = 1;
boolean active = (boolean) flag;  // throws
// after
int flag = 1;
boolean active = (flag != 0);
Defensive patterns

Strategy: validation

Validate before calling

// Never cast to/from boolean. Use explicit comparisons instead:
// int flag = 1;
// boolean active = (flag != 0);

Prevention

When it happens

Trigger: Writing an explicit cast in Painless that involves boolean: 'boolean b = (boolean) 1;' or 'int i = (int) true;'. The compiler's AnalyzerCaster resolves to DefMath.cast, which detects a boolean on either the source or target side and throws.

Common situations: Scripts ported from C/C++/JavaScript where truthiness casts (int->bool, bool->int) are idiomatic. Misunderstanding of Painless's stricter cast rules versus Java autoboxing. Attempts to coerce numeric flags into booleans for conditional logic.

Related errors


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