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
- Replace numeric-to-boolean casts with an explicit comparison: 'boolean b = (x != 0);'.
- Replace boolean-to-numeric casts with a ternary: 'int i = b ? 1 : 0;'.
- 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
- Never write (boolean) or (int)/(long) casts involving boolean.
- Use comparison operators (!= 0) for numeric-to-boolean.
- Use ternary (b ? 1 : 0) for boolean-to-numeric.
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
- Cannot apply [<] operation to type [boolean]
- Cannot apply [<=] operation to type [boolean]
- Cannot apply [>] operation to type [boolean]
- Cannot apply [>=] operation to type [boolean]
- Cannot apply [<<] operation to type [boolean]
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/dcfa332612a216f9.
Report an issue: GitHub.