elastic/elasticsearch · error · ClassCastException

cannot cast java.lang.String with length not equal to one to

Error message

cannot cast java.lang.String with length not equal to one to char

What it means

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.

Source

Thrown at modules/lang-painless/src/main/java/org/elasticsearch/painless/Utility.java:30

/**
 * A set of methods for non-native boxing and non-native
 * exact math operations used at both compile-time and runtime.
 */
public class Utility {

    public static String charToString(final char value) {
        return String.valueOf(value);
    }

    public static char StringTochar(final String value) {
        if (value == null) {
            throw new ClassCastException(
                "cannot cast " + "null " + String.class.getCanonicalName() + " to " + char.class.getCanonicalName()
            );
        }

        if (value.length() != 1) {
            throw new ClassCastException(
                "cannot cast " + String.class.getCanonicalName() + " with length not equal to one to " + char.class.getCanonicalName()
            );
        }

        return value.charAt(0);
    }

    private Utility() {}
}

View on GitHub (pinned to db6a809a66)

Solutions

  1. Guard the cast with a length check: str.length() == 1 ? (char)str : <fallback>.
  2. Constrain the source mapping/data so the value is always exactly one character.
  3. Use str.charAt(0) only after validating length.

Example fix

// before
char c = (char)doc['code'].value; // 'AB' -> 1349
// after
String s = doc['code'].value;
char c = (s != null && s.length() == 1) ? (char)s : '\\0';
Defensive patterns

Strategy: validation

Validate before calling

// Inside the Painless script, guard before casting:
// String s = doc['code'].value;
// if (s != null && s.length() == 1) { char c = (char)s; }

Type guard

// Painless-side guard
String s = doc['code'].value;
boolean isSingleChar = (s != null && s.length() == 1);

Try / catch

try {
    scriptService.run(script, context, vars);
} catch (ScriptException e) {
    if (e.getCause() instanceof ClassCastException ce && ce.getMessage().contains("length not equal to one")) {
        log.warn("multi-char String-to-char in script");
    }
    throw e;
}

Prevention

When it happens

Trigger: 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 ''.

Common situations: 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.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/b11172e04a00f16b. Report an issue: GitHub.