{"record":{"id":"6089b70d2b9ea330","repo":"elastic/elasticsearch","slug":"cannot-convert-to-a-number","errorCode":null,"errorMessage":"Cannot convert [{}] to a Number","messagePattern":"Cannot convert \\[(.+?)\\] to a Number","errorType":"exception","errorClass":"ClassCastException","httpStatus":null,"severity":"error","filePath":"modules/lang-painless/src/main/java/org/elasticsearch/painless/DefMath.java","lineNumber":1228,"sourceCode":"            } else if (clazz == Byte.class) {\n                return getNumber(value).byteValue();\n            } else if (clazz == Character.class) {\n                return (char) getNumber(value).intValue();\n            }\n            return clazz.cast(value);\n        } else {\n            return value;\n        }\n    }\n\n    /** Slowly returns a Number for o. Just for supporting dynamicCast */\n    static Number getNumber(Object o) {\n        if (o instanceof Number) {\n            return (Number) o;\n        } else if (o instanceof Character) {\n            return Integer.valueOf((char) o);\n        } else {\n            throw new ClassCastException(\"Cannot convert [\" + o.getClass() + \"] to a Number\");\n        }\n    }\n\n    private static final MethodHandle DYNAMIC_CAST;\n    private static final MethodHandle DYNAMIC_RECEIVER_CAST;\n    static {\n        final MethodHandles.Lookup methodHandlesLookup = MethodHandles.lookup();\n        try {\n            DYNAMIC_CAST = methodHandlesLookup.findStatic(\n                methodHandlesLookup.lookupClass(),\n                \"dynamicCast\",\n                MethodType.methodType(Object.class, Class.class, Object.class)\n            );\n            DYNAMIC_RECEIVER_CAST = methodHandlesLookup.findStatic(\n                methodHandlesLookup.lookupClass(),\n                \"dynamicReceiverCast\",\n                MethodType.methodType(Object.class, Object.class, Object.class)\n            );","sourceCodeStart":1210,"sourceCodeEnd":1246,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefMath.java#L1210-L1246","documentation":"DefMath.getNumber throws this ClassCastException when dynamicCast (the slow runtime cast used by the def path for compound assignment and explicit casts to a numeric wrapper) receives an object that is neither a Number nor a Character. getNumber is the bridge that converts a dynamic value to Integer/Long/Double/etc. before invoking intValue()/longValue()/doubleValue(). If the object is, say, a String or a List, there is no numeric conversion and the cast cannot proceed.","triggerScenarios":"A def-typed compound assignment or explicit numeric cast where the RHS resolves at runtime to a non-numeric object: 'def x = 'abc'; int i = (int) x;' or 'def x = '5'; def y = 0; y += x;'. dynamicCast calls getNumber, which throws because String is not a Number or Character.","commonSituations":"Scripts that read def values from heterogeneous sources (JSON, doc fields of keyword/text type) and attempt arithmetic casts without validation. Compound assignments (+=, -=) on def variables where the source data is occasionally a string. Migrating scripts that worked on integer fields to keyword fields.","solutions":["Validate or parse the value before the numeric cast: use Integer.parseInt or Double.parseDouble for strings, or check the field mapping.","Avoid def for values that may be non-numeric; use explicit types so the compiler forces consistency.","If the field can hold mixed types, add a runtime type check (instanceof Number) before the cast."],"exampleFix":"// before\ndef x = doc['code'].value;  // keyword field, a String\ndef total = 0;\ntotal += x;  // getNumber throws\n// after\nString x = doc['code'].value;\nint parsed = Integer.parseInt(x);\nint total = 0;\ntotal += parsed;","handlingStrategy":"validation","validationCode":"// Check the value is a Number or Character before numeric cast:\n// def x = doc['code'].value;\n// if (x instanceof Number || x instanceof Character) { int i = ((Number)x).intValue(); } else { /* handle */ }","typeGuard":"// boolean isNumeric = x instanceof Number || x instanceof Character;","tryCatchPattern":null,"preventionTips":["Validate def values with instanceof before numeric casts.","Avoid compound assignment (+=) on def variables sourced from keyword/text fields.","Parse strings with Integer.parseInt/Double.parseDouble instead of casting."],"tags":["painless","elasticsearch","type-error","casting","def-typing","runtime"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:17:08.281Z"}