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

  1. Pass a fully-qualified glibc-style locale including the encoding: 'en_US.UTF-8', 'tr_TR.ISO-8859-9', etc.
  2. Use 'C' (the special-cased POSIX locale with US-ASCII word characters) when no locale-specific behavior is needed
  3. 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

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

Related errors


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/5ae4867c234b0ca7. Report an issue: GitHub.