{"record":{"id":"b11172e04a00f16b","repo":"elastic/elasticsearch","slug":"cannot-cast-java-lang-string-with-length-not-equal","errorCode":null,"errorMessage":"cannot cast java.lang.String with length not equal to one to char","messagePattern":"cannot cast java\\.lang\\.String with length not equal to one to char","errorType":"exception","errorClass":"ClassCastException","httpStatus":null,"severity":"error","filePath":"modules/lang-painless/src/main/java/org/elasticsearch/painless/Utility.java","lineNumber":30,"sourceCode":"/**\n * A set of methods for non-native boxing and non-native\n * exact math operations used at both compile-time and runtime.\n */\npublic class Utility {\n\n    public static String charToString(final char value) {\n        return String.valueOf(value);\n    }\n\n    public static char StringTochar(final String value) {\n        if (value == null) {\n            throw new ClassCastException(\n                \"cannot cast \" + \"null \" + String.class.getCanonicalName() + \" to \" + char.class.getCanonicalName()\n            );\n        }\n\n        if (value.length() != 1) {\n            throw new ClassCastException(\n                \"cannot cast \" + String.class.getCanonicalName() + \" with length not equal to one to \" + char.class.getCanonicalName()\n            );\n        }\n\n        return value.charAt(0);\n    }\n\n    private Utility() {}\n}\n","sourceCodeStart":12,"sourceCodeEnd":40,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/lang-painless/src/main/java/org/elasticsearch/painless/Utility.java#L12-L40","documentation":"The companion check in Utility.StringTochar: the String is non-null but its length is not exactly 1, so it cannot be narrowed to a single char. Throws ClassCastException at script runtime.","triggerScenarios":"A Painless script casts a multi-character (or empty) String to char via (char)str; e.g. doc['code'].value where the field holds 'AB' or ''.","commonSituations":"Indexing free-text fields and then casting them to char in a script; runtime fields over string data whose length is not constrained to 1; bad test fixture data.","solutions":["Guard the cast with a length check: str.length() == 1 ? (char)str : <fallback>.","Constrain the source mapping/data so the value is always exactly one character.","Use str.charAt(0) only after validating length."],"exampleFix":"// before\nchar c = (char)doc['code'].value; // 'AB' -> 1349\n// after\nString s = doc['code'].value;\nchar c = (s != null && s.length() == 1) ? (char)s : '\\\\0';","handlingStrategy":"validation","validationCode":"// Inside the Painless script, guard before casting:\n// String s = doc['code'].value;\n// if (s != null && s.length() == 1) { char c = (char)s; }","typeGuard":"// Painless-side guard\nString s = doc['code'].value;\nboolean isSingleChar = (s != null && s.length() == 1);","tryCatchPattern":"try {\n    scriptService.run(script, context, vars);\n} catch (ScriptException e) {\n    if (e.getCause() instanceof ClassCastException ce && ce.getMessage().contains(\"length not equal to one\")) {\n        log.warn(\"multi-char String-to-char in script\");\n    }\n    throw e;\n}","preventionTips":["Validate String length is exactly 1 before casting to char.","Use a keyword mapping with a length constraint if the field feeds a char cast.","Prefer explicit charAt(0) with a guard over an unchecked cast."],"tags":["painless","scripting","runtime","cast","elasticsearch"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}