dotnet/runtime · error · Error

Locale info for locale=

Error message

Locale info for locale=${localeName} is null or empty.

What it means

After resolving LanguageName and RegionName through Intl.DisplayNames, the code joins them with '##'. If the resulting string is empty (both names were undefined/empty) this error fires. It means the Intl provider accepted the locale and culture but returned no display text for either component.

Solutions

  1. Use full-icu / a Node build with complete ICU data so Intl.DisplayNames has entries for the locale.
  2. Switch the culture to a well-known locale with full display-name coverage (e.g. en-US, fr-FR) to confirm the path works, then narrow down the unsupported locale.
  3. On the .NET side, fall back to a parent/neutral culture (e.g. 'en' instead of 'en-xxx') when display names are unavailable.

Example fix

// before: locale with no display-name data
var ci = new CultureInfo("qaa-RU");

// after: well-known locale with ICU coverage
var ci = new CultureInfo("ru-RU");
Defensive patterns

Strategy: validation

Validate before calling

// Probe Intl.DisplayNames coverage for a locale/culture before relying on it.
function hasDisplayNames(locale: string, culture: string): boolean {
  try {
    const lang = new Intl.DisplayNames([culture], { type: "language" }).of(locale);
    return typeof lang === "string" && lang.length > 0;
  } catch {
    return false;
  }
}

if (!hasDisplayNames(target, uiCulture)) {
  target = "en"; // fallback with known coverage
}

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: Intl.DisplayNames([cultureName], {type:'region'}).of(region) and the language variant both return undefined or empty, producing an empty join. Happens with locales whose region/script the runtime's Intl data does not have display names for.

Common situations: Running on a JS engine with reduced ICU data (older Node without full-icu, embedded WebView) where DisplayNames has no data for the requested language/region; a private-use or rare locale (e.g. 'qaa-RU') that canonicalizes but has no display strings.

Related errors


AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10). Data as JSON: /api/errors/0b87e21b16939fbc. Report an issue: GitHub.

Appendix: source

Thrown at src/native/libs/System.Native.Browser/native/globalization-locale.ts:63

                        // handle non-standard or malformed locales by forwarding the locale code, e.g. "xx-u-xx"
                        _ems_.dotnetBrowserUtilsExports.stringToUTF16(dst, dst + 2 * localeNameOriginal.length, localeNameOriginal);
                        _ems_.dotnetApi.setHeapI32(dstLength, localeNameOriginal.length);
                        return 0 as any;
                    }
                    throw error;
                }
            } else {
                throw error;
            }
        }
        const localeInfo = {
            LanguageName: languageName,
            RegionName: regionName,
        };
        const result = Object.values(localeInfo).join(OUTER_SEPARATOR);

        if (!result)
            throw new Error(`Locale info for locale=${localeName} is null or empty.`);

        if (result.length > dstMaxLength)
            throw new Error(`Locale info for locale=${localeName} exceeds length of ${dstMaxLength}.`);

        _ems_.dotnetBrowserUtilsExports.stringToUTF16(dst, dst + 2 * result.length, result);
        _ems_.dotnetApi.setHeapI32(dstLength, result.length);
        return 0 as any;
    } catch (ex: any) {
        _ems_.dotnetApi.setHeapI32(dstLength, -1);
        return _ems_.dotnetBrowserUtilsExports.stringToUTF16Ptr(ex.toString());
    }

    function normalizeLocale(locale: string | null) {
        if (!locale)
            return undefined;
        try {
            locale = locale.toLocaleLowerCase().replace("_", "-");
            if (locale.startsWith("zh-")) {

View on GitHub (pinned to 60108ba66e)