{"record":{"id":"a8d98c28ea12a30a","repo":"dotnet/runtime","slug":"locale-or-culture-name-is-null-or-empty-localenam-a8d98c","errorCode":null,"errorMessage":"Locale or culture name is null or empty. localeName=${localeName}, cultureName=${cultureName}","messagePattern":"Locale or culture name is null or empty\\. localeName=(.+?), cultureName=(.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/native/libs/System.Native.Browser/native/globalization-locale.ts","lineNumber":23,"sourceCode":"import { _ems_ } from \"../../Common/JavaScript/ems-ambient\";\n\n// char16_t* SystemJS_GetLocaleInfo (const uint16_t* locale, int32_t localeLength, const uint16_t* culture, int32_t cultureLength, const uint16_t* result, int32_t resultMaxLength, int *resultLength);\nexport function SystemJS_GetLocaleInfo(culture: number, cultureLength: number, locale: number, localeLength: number, dst: number, dstMaxLength: number, dstLength: Int32Ptr): VoidPtr {\n    const OUTER_SEPARATOR = \"##\";\n    try {\n        const localeNameOriginal = _ems_.dotnetBrowserUtilsExports.utf16ToString(<any>locale, <any>(locale + 2 * localeLength));\n        const localeName = normalizeLocale(localeNameOriginal);\n        if (!localeName && localeNameOriginal) {\n            // handle non-standard or malformed locales by forwarding the locale code\n            _ems_.dotnetBrowserUtilsExports.stringToUTF16(dst, dst + 2 * localeNameOriginal.length, localeNameOriginal);\n            _ems_.dotnetApi.setHeapI32(dstLength, localeNameOriginal.length);\n            return 0 as any;\n        }\n        const cultureNameOriginal = _ems_.dotnetBrowserUtilsExports.utf16ToString(<any>culture, <any>(culture + 2 * cultureLength));\n        const cultureName = normalizeLocale(cultureNameOriginal);\n\n        if (!localeName || !cultureName)\n            throw new Error(`Locale or culture name is null or empty. localeName=${localeName}, cultureName=${cultureName}`);\n\n        const localeParts = localeName.split(\"-\");\n        // cultureName can be in a form of:\n        // 1) \"language\", e.g. \"zh\"\n        // 2) \"language-region\", e.g. \"zn-CN\"\n        // 3) \"language-script-region\", e.g. \"zh-Hans-CN\"\n        // 4) \"language-script\", e.g. \"zh-Hans\" (served in the catch block below)\n        let languageName, regionName;\n        try {\n            const region = localeParts.length > 1 ? localeParts.pop() : undefined;\n            // this line might fail if form 4 from the comment above is used:\n            regionName = region ? new Intl.DisplayNames([cultureName], { type: \"region\" }).of(region) : undefined;\n            const language = localeParts.join(\"-\");\n            languageName = new Intl.DisplayNames([cultureName], { type: \"language\" }).of(language);\n        } catch (error) {\n            if (error instanceof RangeError) {\n                // if it failed from this reason then cultureName is in a form \"language-script\", without region\n                try {","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/dotnet/runtime/blob/60108ba66eb7d1d12f595480091b4ad80a24b172/src/native/libs/System.Native.Browser/native/globalization-locale.ts#L5-L41","documentation":"SystemJS_GetLocaleInfo is the interop entry the runtime calls to resolve locale display names via Intl.DisplayNames. After normalizeLocale() runs on both the locale and culture strings, if either result is falsy this error is thrown. normalizeLocale() returns undefined for empty input or for strings Intl.getCanonicalLocales() rejects (e.g. 'xx-u-xx' handled only as a fallback earlier).","triggerScenarios":"The .NET runtime passes a locale or culture string that is empty, whitespace-only, or so malformed that Intl.getCanonicalLocales() throws and the catch returns undefined for both. The malformed-locale forwarding at lines 13-18 only triggers when localeNameOriginal is truthy; if the original was empty the guard at line 22 fires.","commonSituations":"Thread.CurrentCulture or CurrentUICulture set to a CultureInvariant/empty culture on the server then serialized to the WASM client; a locale string arriving as '' from configuration; ICU/globalization data not loaded so the runtime resolves to an invariant culture; headless/Node host where Intl data is incomplete.","solutions":["Ensure the .NET app sets an explicit, valid culture (e.g. new CultureInfo(\"en-US\")) rather than relying on invariant/empty defaults before code that triggers locale lookup runs.","If running under Node.js, use a full-icu build (npm i full-icu) so Intl.getCanonicalLocales and DisplayNames resolve real locales.","Check that user-supplied locale strings from headers/URLs are validated against a known list before being assigned to CurrentCulture/CurrentUICulture.","If a genuinely non-standard locale is expected, pass it in a form normalizeLocale can canonicalize (BCP-47 language-region), not an empty string."],"exampleFix":"// before\nCultureInfo.CurrentCulture = CultureInfo.InvariantCulture; // empty name path\n\n// after\nCultureInfo.CurrentCulture = new CultureInfo(\"en-US\");","handlingStrategy":"validation","validationCode":"// Validate a locale string before the runtime uses it for display-name lookup.\nfunction isValidLocaleName(s: string | undefined | null): s is string {\n  if (!s || !s.trim()) return false;\n  try {\n    const c = (Intl as any).getCanonicalLocales(s.replace(\"_\", \"-\"));\n    return Array.isArray(c) && c.length > 0;\n  } catch {\n    return false;\n  }\n}\n\nif (!isValidLocaleName(userLocale)) {\n  userLocale = \"en-US\"; // safe fallback\n}","typeGuard":"function isNonEmptyLocale(s: any): s is string {\n  return typeof s === \"string\" && s.trim().length > 0;\n}","tryCatchPattern":"null","preventionTips":["Set explicit, valid CultureInfo values rather than invariant/empty defaults.","Under Node, use a full-icu build so Intl can resolve real locales.","Validate any user/header/URL-sourced locale against a known BCP-47 list before assigning it.","Avoid passing private-use or empty locale strings to interop that triggers locale lookup."],"tags":["globalization","locale","i18n","culture","intl"],"backgroundTag":null,"analyzedSha":"60108ba66eb7d1d12f595480091b4ad80a24b172","analyzedAt":"2026-08-10T18:54:11.478Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}