{"record":{"id":"c5e9760080fb0440","repo":"elastic/elasticsearch","slug":"cannot-apply-operation-to-type-boolean-c5e976","errorCode":null,"errorMessage":"Cannot apply [<] operation to type [boolean]","messagePattern":"Cannot apply \\[<\\] operation to type \\[boolean\\]","errorType":"exception","errorClass":"ClassCastException","httpStatus":null,"severity":"error","filePath":"modules/lang-painless/src/main/java/org/elasticsearch/painless/DefMath.java","lineNumber":608,"sourceCode":"\n    private static boolean lt(int a, int b) {\n        return a < b;\n    }\n\n    private static boolean lt(long a, long b) {\n        return a < b;\n    }\n\n    private static boolean lt(float a, float b) {\n        return a < b;\n    }\n\n    private static boolean lt(double a, double b) {\n        return a < b;\n    }\n\n    private static boolean lt(boolean a, boolean b) {\n        throw new ClassCastException(\"Cannot apply [<] operation to type [boolean]\");\n    }\n\n    private static boolean lt(Object left, Object right) {\n        if (left instanceof Number) {\n            if (right instanceof Number) {\n                if (left instanceof Double || right instanceof Double) {\n                    return ((Number) left).doubleValue() < ((Number) right).doubleValue();\n                } else if (left instanceof Float || right instanceof Float) {\n                    return ((Number) left).floatValue() < ((Number) right).floatValue();\n                } else if (left instanceof Long || right instanceof Long) {\n                    return ((Number) left).longValue() < ((Number) right).longValue();\n                } else {\n                    return ((Number) left).intValue() < ((Number) right).intValue();\n                }\n            } else if (right instanceof Character) {\n                if (left instanceof Double) {\n                    return ((Number) left).doubleValue() < (char) right;\n                } else if (left instanceof Long) {","sourceCodeStart":590,"sourceCodeEnd":626,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefMath.java#L590-L626","documentation":"Thrown by DefMath.lt(boolean, boolean) which unconditionally throws. The Painless compiler's promote() method maps a (boolean, boolean) pair to boolean.class, so the less-than operator dispatches to this overload at compile time. Unlike Java which rejects this at compile time, Painless defers it to a runtime ClassCastException because the method table must include a boolean slot for every operator.","triggerScenarios":"A Painless script applies the < operator to two operands that are both statically typed as boolean. The compiler resolves both to boolean.class, binary promotion yields boolean.class, and the lt(boolean, boolean) overload is selected.","commonSituations":"Comparing two boolean fields or flags with < instead of a logical operator; attempting to sort or rank by a boolean field; copy-pasting comparison logic from numeric code into a boolean context; runtime field mapped as boolean used in a relational comparison.","solutions":["Replace the relational comparison with a logical operator: use == , != , or conditional logic instead of <","Convert booleans to integers before comparing: int ia = a ? 1 : 0; int ib = b ? 1 : 0; then compare ia < ib","Re-examine the field mapping — if ordering is needed, the field should be numeric, not boolean"],"exampleFix":"// before\nboolean isActive = doc['active'].value;\nboolean isVerified = doc['verified'].value;\nboolean result = isActive < isVerified;\n\n// after\nint activeFlag = doc['active'].value ? 1 : 0;\nint verifiedFlag = doc['verified'].value ? 1 : 0;\nboolean result = activeFlag < verifiedFlag;","handlingStrategy":"type-guard","validationCode":"// Before comparing booleans, convert to integers if ordering is needed\nboolean a = doc['flag1'].value;\nboolean b = doc['flag2'].value;\nint ia = a ? 1 : 0;\nint ib = b ? 1 : 0;\n// Now safe to use relational operators\nreturn ia < ib;","typeGuard":"// Check if a type supports relational comparison\nboolean isRelationalComparable(Class<?> clazz) {\n  return clazz == int.class || clazz == long.class || \n         clazz == float.class || clazz == double.class ||\n         clazz == char.class;\n}","tryCatchPattern":null,"preventionTips":["Never apply <, <=, >, >= to boolean fields — use == or != instead","If boolean ordering is needed, convert to 0/1 integers explicitly","Review script logic when refactoring from numeric to boolean fields","Use the Painless compiler's type checking by declaring explicit types instead of def"],"tags":["painless","elasticsearch","boolean","type-error","comparison","runtime","less-than"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}