oracle/graal · error · IllegalArgumentException
malformed locale: %s
Error message
malformed locale: %s
What it means
Thrown by PythonLocaleData.getLocaleData when a locale string other than 'C' contains no '.' separator. The method expects the C-library form '<language>_<region>.<encoding>' (e.g. 'tr_TR.UTF-8'); without a dot it cannot split language from encoding and throws IllegalArgumentException('malformed locale: ...') before any charset lookup.
Source
Thrown at regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/flavor/python/PythonLocaleData.java:86
public final class PythonLocaleData {
private static final int CACHE_SIZE = 16;
private static final LRUCache<CacheKey, PythonLocaleData> CACHED_LOCALE_DATA = new LRUCache<>(CACHE_SIZE);
private static final CodePointSet WORD_CHARS = UNICODE.getProperty("Alphabetic").union(UNICODE.getProperty("gc=digit")).union(CodePointSet.create('_'));
private final CodePointSet wordChars;
private final CodePointSet nonWordChars;
private final byte[] caseFolding;
public static PythonLocaleData getLocaleData(String locale) {
if (locale.equals("C")) {
return createCachedLocaleData(false, Charset.forName("US-ASCII"));
} else {
int dot = locale.indexOf('.');
if (dot == -1) {
throw new IllegalArgumentException("malformed locale: " + locale);
}
String language = locale.substring(0, dot);
String encoding = locale.substring(dot + 1);
try {
return createCachedLocaleData(language.startsWith("tr_"), Charset.forName(encoding));
} catch (UnsupportedCharsetException | IllegalCharsetNameException e) {
throw new IllegalArgumentException("unsupported locale: " + locale);
}
}
}
public CodePointSet getWordCharacters() {
return wordChars;
}
public CodePointSet getNonWordCharacters() {
return nonWordChars;
}View on GitHub (pinned to a66e9ccd1d)
Solutions
- Pass a fully-qualified glibc-style locale including the encoding: 'en_US.UTF-8', 'tr_TR.ISO-8859-9', etc.
- Use 'C' (the special-cased POSIX locale with US-ASCII word characters) when no locale-specific behavior is needed
- Normalize locale strings at the call site: if the string has no '.', append '.UTF-8' (or map known bare tags to full names) before calling getLocaleData
Example fix
// before
PythonLocaleData.getLocaleData("tr_TR"); // no encoding part
// after
PythonLocaleData.getLocaleData("tr_TR.UTF-8"); Defensive patterns
Strategy: validation
Validate before calling
boolean isValidPythonLocale(String locale) {
return locale.equals("C") || (locale.indexOf('.') > 0 && locale.indexOf('.') < locale.length() - 1);
} Prevention
- Always pass glibc-style '<lang>_<REGION>.<encoding>' strings (or 'C') to Python locale handling
- Normalize locale identifiers at your system boundary: bare language tags get '.UTF-8' appended
When it happens
Trigger: Calling the Python-flavor regex locale support (locale-dependent \\w, \\b, case folding) with a string like 'en', 'tr_TR', or 'POSIX' — anything that is not exactly 'C' and has no '.' character. locale.indexOf('.') returns -1 and the exception is thrown.
Common situations: Forwarding Python's locale.getlocale()/os.environ['LC_CTYPE'] output that lacks an encoding part; passing IETF-style tags ('en-US', 'tr') or bare language names ('Turkish') instead of glibc-style names; default-locale code paths in GraalVM Python guest applications.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- unsupported locale: %s
- Bad pattern: {}
- invalid double value: "%s"
- The argument '%s' could not be parsed: %s
- Syntax '{}' not recognized
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/5ae4867c234b0ca7.
Report an issue: GitHub.