dotnet/runtime · error · Error

Locale or culture name is null or empty. localeName=${locale

Error message

Locale or culture name is null or empty. localeName=${localeName}, cultureName=${cultureName}

What it means

Thrown by SystemJS_GetLocaleInfo() in globalization-locale.ts when, after normalizeLocale() runs, either localeName or cultureName is falsy. normalizeLocale lowercases, fixes zh- legacy codes, and runs Intl.getCanonicalLocales, returning undefined on any failure or empty input. So this error means the locale/culture passed from the .NET side could not be canonicalized into a valid BCP-47 locale AND could not be forwarded as a raw fallback. Note: the surrounding try/catch converts this into an error string returned to native (sets dstLength=-1), so it does not crash JS but signals a globalization failure to the runtime.

Source

Thrown at src/mono/browser/runtime/globalization-locale.ts:42

        return undefined;
    }
}

export function SystemJS_GetLocaleInfo (culture: number, cultureLength: number, locale: number, localeLength: number, dst: number, dstMaxLength: number, dstLength: Int32Ptr): VoidPtr {
    try {
        const localeNameOriginal = utf16ToString(<any>locale, <any>(locale + 2 * localeLength));
        const localeName = normalizeLocale(localeNameOriginal);
        if (!localeName && localeNameOriginal) {
            // handle non-standard or malformed locales by forwarding the locale code
            stringToUTF16(dst, dst + 2 * localeNameOriginal.length, localeNameOriginal);
            setI32(dstLength, localeNameOriginal.length);
            return VoidPtrNull;
        }
        const cultureNameOriginal = utf16ToString(<any>culture, <any>(culture + 2 * cultureLength));
        const cultureName = normalizeLocale(cultureNameOriginal);

        if (!localeName || !cultureName)
            throw new Error(`Locale or culture name is null or empty. localeName=${localeName}, cultureName=${cultureName}`);

        const localeParts = localeName.split("-");
        // cultureName can be in a form of:
        // 1) "language", e.g. "zh"
        // 2) "language-region", e.g. "zn-CN"
        // 3) "language-script-region", e.g. "zh-Hans-CN"
        // 4) "language-script", e.g. "zh-Hans" (served in the catch block below)
        let languageName, regionName;
        try {
            const region = localeParts.length > 1 ? localeParts.pop() : undefined;
            // this line might fail if form 4 from the comment above is used:
            regionName = region ? new Intl.DisplayNames([cultureName], { type: "region" }).of(region) : undefined;
            const language = localeParts.join("-");
            languageName = new Intl.DisplayNames([cultureName], { type: "language" }).of(language);
        } catch (error) {
            if (error instanceof RangeError) {
                // if it failed from this reason then cultureName is in a form "language-script", without region
                try {

View on GitHub (pinned to 290d5ab72c)

Solutions

  1. If you intend invariant globalization, set globalizationMode to invariant / DOTNET_GLOBALIZATION_MODE=invariant so the runtime does not request locale info.
  2. Provide a valid culture (e.g. en-US) explicitly via application configuration / browser locale rather than relying on an empty default.
  3. Ensure the ICU data (sharded/all) is loaded if you need real culture resolution; without ICU the runtime may pass empty culture strings.
  4. Update the browser/runtime if a specific locale fails canonicalization in an older Intl implementation.

Example fix

// before: app runs with no culture, invariant not declared
// runtime calls SystemJS_GetLocaleInfo with empty culture -> error string returned

// after: declare invariant mode or supply a culture
// option A - invariant (no ICU needed)
//   DOTNET_GLOBALIZATION_MODE=invariant  (or globalizationMode: 'invariant' in config)
// option B - explicit culture with ICU
//   set thread culture to 'en-US' in your .NET app
Defensive patterns

Strategy: fallback

Validate before calling

function resolveCultureOrDefault(culture?: string | null): string {
  if (!culture) return 'en-US'; // or use invariant mode
  try { Intl.getCanonicalLocales(culture); return culture; }
  catch { return 'en-US'; }
}

Type guard

function isValidCulture(c: unknown): boolean {
  if (typeof c !== 'string' || !c) return false;
  try { Intl.getCanonicalLocales(c); return true; } catch { return false; }
}

Try / catch

null

Prevention

When it happens

Trigger: The runtime requesting locale/culture info with an empty, whitespace, or malformed culture string that normalizeLocale rejects (returns undefined) while the original was also empty (so the forwarding branch is skipped). A truly empty cultureName passed by the globalization layer when invariant/empty culture was not intended.

Common situations: Running in invariant globalization mode where culture strings are empty and the runtime still queries locale info. A user/OS culture that resolves to an empty or non-canonical string in this browser. Browser/Intl differences (older engines) rejecting a locale that the runtime expected to work. Custom cultureName overrides that pass an invalid value.

Related errors


AI-assisted analysis of dotnet/runtime@290d5ab72c (2026-08-06). Data as JSON: /api/errors/19e33c8f72572fd0. Report an issue: GitHub.