{"record":{"id":"e02e47d28e4c7a16","repo":"elastic/elasticsearch","slug":"cannot-apply-operator-to-type","errorCode":null,"errorMessage":"Cannot apply operator [{}] to type [{}]","messagePattern":"Cannot apply operator \\[(.+?)\\] to type \\[(.+?)\\]","errorType":"exception","errorClass":"ClassCastException","httpStatus":null,"severity":"error","filePath":"modules/lang-painless/src/main/java/org/elasticsearch/painless/DefMath.java","lineNumber":1159,"sourceCode":"                    map.put(\"lt\", PRIVATE_METHOD_HANDLES_LOOKUP.findStatic(clazz, \"lt\", comparison));\n                    map.put(\"lte\", PRIVATE_METHOD_HANDLES_LOOKUP.findStatic(clazz, \"lte\", comparison));\n                    map.put(\"gt\", PRIVATE_METHOD_HANDLES_LOOKUP.findStatic(clazz, \"gt\", comparison));\n                    map.put(\"gte\", PRIVATE_METHOD_HANDLES_LOOKUP.findStatic(clazz, \"gte\", comparison));\n                    map.put(\"lsh\", PRIVATE_METHOD_HANDLES_LOOKUP.findStatic(clazz, \"lsh\", shift));\n                    map.put(\"rsh\", PRIVATE_METHOD_HANDLES_LOOKUP.findStatic(clazz, \"rsh\", shift));\n                    map.put(\"ush\", PRIVATE_METHOD_HANDLES_LOOKUP.findStatic(clazz, \"ush\", shift));\n                    return map;\n                } catch (ReflectiveOperationException e) {\n                    throw new AssertionError(e);\n                }\n            }))\n    );\n\n    /** Returns an appropriate method handle for a unary or shift operator, based only on the receiver (LHS) */\n    public static MethodHandle lookupUnary(Class<?> receiverClass, String name) {\n        MethodHandle handle = TYPE_OP_MAPPING.get(promote(unbox(receiverClass))).get(name);\n        if (handle == null) {\n            throw new ClassCastException(\"Cannot apply operator [\" + name + \"] to type [\" + receiverClass + \"]\");\n        }\n        return handle;\n    }\n\n    /** Returns an appropriate method handle for a binary operator, based on promotion of the LHS and RHS arguments */\n    public static MethodHandle lookupBinary(Class<?> classA, Class<?> classB, String name) {\n        MethodHandle handle = TYPE_OP_MAPPING.get(promote(promote(unbox(classA)), promote(unbox(classB)))).get(name);\n        if (handle == null) {\n            throw new ClassCastException(\"Cannot apply operator [\" + name + \"] to types [\" + classA + \"] and [\" + classB + \"]\");\n        }\n        return handle;\n    }\n\n    /** Returns a generic method handle for any operator, that can handle all valid signatures, nulls, corner cases */\n    public static MethodHandle lookupGeneric(String name) {\n        return TYPE_OP_MAPPING.get(Object.class).get(name);\n    }\n","sourceCodeStart":1141,"sourceCodeEnd":1177,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefMath.java#L1141-L1177","documentation":"DefMath.lookupUnary throws this ClassCastException at compile/link time when no method handle is registered in TYPE_OP_MAPPING for the (promoted, unboxed) receiver type of a unary or shift operator. The mapping table only contains entries for boolean, int, long, float, double, and Object. If the receiver class promotes/unboxes to something with no entry for the requested operator name (e.g. a shift on a promoted float that has no valid handle, or an unknown operator name), the lookup returns null and this error fires.","triggerScenarios":"Compiling a Painless script where a unary or shift operator is applied to a statically-typed receiver for which the operator has no registered handle. For example, applying a bitwise NOT or shift to a float/double typed variable (not def) — the compiler resolves the operator via lookupUnary and finds null because only the throwing stubs are registered under those types and the stub is not what the typed path selects.","commonSituations":"Scripts that attempt unary bitwise/shift operations on floating-point typed variables. Custom operator names or internal compiler bugs that pass an unregistered operator string. Edge cases during language version upgrades where operator registration changed.","solutions":["Check the receiver type in the script; for shift/bitwise ops it must be int or long. Cast or redeclare accordingly.","Verify the operator is valid for the type (e.g. '!' is for boolean, '~' is for integers).","If this fires unexpectedly on valid code, suspect a Painless compiler regression and check the operator name spelling in the compiler against TYPE_OP_MAPPING keys (not, neg, plus, lsh, rsh, ush, etc.)."],"exampleFix":"// before\nfloat x = 1.5f;\nint y = x >> 2;  // no handle for float shift\n// after\nint x = 1;\nint y = x >> 2;","handlingStrategy":"validation","validationCode":"// Before writing a unary/shift op, confirm the operand type is int or long:\n// int x = 5; // valid for ~x, -x, x << 1\n// float x = 1.5f; // INVALID for any shift or bitwise unary","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Restrict bitwise/unary operators to int and long typed variables.","Let the compiler catch type errors by using explicit types instead of def.","Consult the Painless operator table to know which operators apply to which types."],"tags":["painless","elasticsearch","type-error","operator-resolution","compile-time"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}