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
SystemJS_GetLocaleInfo normalizes both the locale and culture strings via Intl.getCanonicalLocales; if either resolves to undefined (unparseable, non-canonical, or empty after normalization) it throws this. The surrounding try/catch catches it, sets dstLength to -1, and marshals the message back to .NET as a locale-resolution failure rather than crashing the runtime.
Source
Thrown at src/native/libs/System.Native.Browser/native/globalization-locale.ts:23
import { _ems_ } from "../../Common/JavaScript/ems-ambient";
// 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);
export function SystemJS_GetLocaleInfo(culture: number, cultureLength: number, locale: number, localeLength: number, dst: number, dstMaxLength: number, dstLength: Int32Ptr): VoidPtr {
const OUTER_SEPARATOR = "##";
try {
const localeNameOriginal = _ems_.dotnetBrowserUtilsExports.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
_ems_.dotnetBrowserUtilsExports.stringToUTF16(dst, dst + 2 * localeNameOriginal.length, localeNameOriginal);
_ems_.dotnetApi.setHeapI32(dstLength, localeNameOriginal.length);
return 0 as any;
}
const cultureNameOriginal = _ems_.dotnetBrowserUtilsExports.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
- Set an explicit, valid culture in the .NET app (e.g. Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US")) before calling locale/globalization APIs.
- Ensure the browser/Node host has full ICU data (Node built with --with-intl=full-icu, not the default small-icu) so getCanonicalLocales and DisplayNames resolve.
- Sanitize user-supplied locale strings to a known-good fallback before they reach globalization.
Example fix
// before
var ci = new CultureInfo(""); // empty culture -> null/empty locale -> throw
// after
var ci = new CultureInfo("en-US"); Defensive patterns
Strategy: validation
Validate before calling
function isValidLocale(s) {
if (!s) return false;
try { return Intl.getCanonicalLocales(s).length > 0; }
catch { return false; }
}
if (!isValidLocale(locale) || !isValidLocale(culture)) useFallbackCulture(); Try / catch
// .NET caller: GetLocaleInfo sets *dstLength = -1 on failure; check the returned length
int len = SystemJS_GetLocaleInfo(...);
if (len < 0) { /* marshaled error string; fall back to invariant culture */ } Prevention
- Default to a concrete culture like en-US rather than relying on host-detected empty cultures.
- Bundle full ICU data in Node/WASM hosts used for globalization.
- Sanitize user-supplied locale strings to a known-good value before they reach the runtime.
When it happens
Trigger: Passing a locale or culture string to the native locale-info call that Intl.getCanonicalLocales rejects or trims to empty — e.g. " ", "INVALID", an uncanonical "xx-YY", or a culture that normalizeLocale maps to undefined.
Common situations: A .NET WASM app whose host supplies an empty CurrentCulture/CurrentUICulture (server/SSR environment without LANG/UCOM culture), a user-supplied culture textbox, or a host running with reduced ICU data where getCanonicalLocales fails on valid-looking tags.
Related errors
- Locale info for locale=${localeName} is null or empty.
- Locale or culture name is null or empty. localeName=${locale
- Locale info for locale=${localeName} exceeds length of ${dst
- Failed to load ICU data
- invariant globalization mode is inactive and no ICU data arc
AI-assisted analysis of dotnet/runtime@290d5ab72c (2026-08-06).
Data as JSON: /api/errors/a8d98c28ea12a30a.
Report an issue: GitHub.