dotnet/runtime · error · Error

invariant globalization mode is inactive and no ICU data arc

Error message

invariant globalization mode is inactive and no ICU data archives are available

What it means

init_globalization throws when globalizationMode is set to a non-invariant mode (sharded, all, or custom) but no ICU data archive could be resolved, so preferredIcuAsset is null. The loader only auto-falls-back to invariant for the undefined/auto modes; an explicit sharded/all/custom request with missing ICU data is treated as a hard failure because culture APIs would be broken.

Source

Thrown at src/mono/browser/runtime/loader/icu.ts:23

import { GlobalizationMode, MonoConfig } from "../types";
import { ENVIRONMENT_IS_WEB, loaderHelpers } from "./globals";
import { mono_log_info, mono_log_debug } from "./logging";

export function init_globalization () {
    loaderHelpers.preferredIcuAsset = getIcuResourceName(loaderHelpers.config);
    let invariantMode = loaderHelpers.config.globalizationMode == GlobalizationMode.Invariant;

    if (!invariantMode) {
        if (loaderHelpers.preferredIcuAsset) {
            mono_log_debug("ICU data archive(s) available, disabling invariant mode");
        } else if (loaderHelpers.config.globalizationMode !== GlobalizationMode.Custom && loaderHelpers.config.globalizationMode !== GlobalizationMode.All && loaderHelpers.config.globalizationMode !== GlobalizationMode.Sharded) {
            mono_log_debug("ICU data archive(s) not available, using invariant globalization mode");
            invariantMode = true;
            loaderHelpers.preferredIcuAsset = null;
        } else {
            const msg = "invariant globalization mode is inactive and no ICU data archives are available";
            mono_log_error(`ERROR: ${msg}`);
            throw new Error(msg);
        }
    }

    const invariantEnv = "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT";
    const env_variables = loaderHelpers.config.environmentVariables!;
    if (env_variables[invariantEnv] === undefined && invariantMode) {
        env_variables[invariantEnv] = "1";
    }
    if (env_variables["TZ"] === undefined) {
        try {
            // this call is relatively expensive, so we call it during download of other assets
            const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || null;
            if (timezone) {
                env_variables!["TZ"] = timezone;
            }
        } catch {
            mono_log_info("failed to detect timezone, will fallback to UTC");
        }

View on GitHub (pinned to 290d5ab72c)

Solutions

  1. If you do not need culture data: set globalizationMode to 'invariant' (or InvariantGlobalization=true) and republish so the runtime uses the invariant fallback.
  2. If you need globalization: remove InvariantGlobalization, keep globalizationMode at sharded/all/custom, and verify the icudt*.dat file appears under _framework/ and is listed in the generated mono-config's resources.icu.
  3. For custom mode, confirm the custom ICU file is present in resources and its name matches getIcuResourceName's first-entry selection.

Example fix

// before: config globalizationMode 'sharded' but no icu asset shipped
// mono-config.json
"globalizationMode": "sharded"
// after
"globalizationMode": "invariant"
Defensive patterns

Strategy: validation

Validate before calling

// Inspect the generated mono-config before startup to confirm ICU assets exist for the requested mode.
const cfg = monoConfig; // the config object passed to the runtime
const mode = cfg.globalizationMode;
const hasIcu = Array.isArray(cfg.resources?.icu) && cfg.resources.icu.length > 0;
if ((mode === 'sharded' || mode === 'all' || mode === 'custom') && !hasIcu) {
  throw new Error(`globalizationMode '${mode}' requires ICU data that is missing; use 'invariant' or ship icudt assets.`);
}

Try / catch

// init_globalization runs during create(); catch and fall back to invariant.
try {
  await dotnet.create();
} catch (e) {
  if (String(e?.message).includes('no ICU data archives are available')) {
    config.globalizationMode = 'invariant';
    await dotnet.create(); // retry with invariant
  } else throw e;
}

Prevention

When it happens

Trigger: config.globalizationMode is 'sharded', 'all', or 'custom' but config.resources.icu is empty or the expected file (icudt.dat / the sharded icudt_EFIGS.dat|icudt_CJK.dat|icudt_no_CJK.dat / a custom file) is absent, so getIcuResourceName returns null and the else-branch in init_globalization fires.

Common situations: Setting <InvariantGlobalization>true</InvariantGlobalization> in the project while a runtime config still requests sharded/all ICU; publishing with trimmed resources so icudt*.dat is stripped; a custom ICU file path that does not resolve; upgrading versions where ICU asset naming or sharding changed.

Related errors


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