dotnet/runtime · error · Error

Failed to initialize ICU data

Error message

Failed to initialize ICU data

What it means

Thrown by loadIcuData after the native _wasm_load_icu_data call returns a falsy result. ICU data (icudt.dat) provides Unicode/globalization support (culture-aware casing, collation, calendars) to the .NET WASM runtime; without it, System.Globalization fails. The native loader rejected the bytes it was handed.

Source

Thrown at src/native/libs/Common/JavaScript/host/assets.ts:125

    _ems_.HEAPU32[outSize as any >>> 2] = 0;
    _ems_.HEAPU32[((outSize as any) + 4) >>> 2] = 0;
    return false;
}

export function loadIcuData(bytes: Uint8Array) {
    const sp = _ems_.stackSave();
    try {
        const ptrPtr = _ems_.stackAlloc(sizeOfPtr);
        if (_ems_._posix_memalign(ptrPtr as any, 16, bytes.length)) {
            throw new Error("posix_memalign failed for ICU data");
        }

        const ptr = _ems_.HEAPU32[ptrPtr as any >>> 2];
        _ems_.HEAPU8.set(bytes, ptr >>> 0);

        const result = _ems_._wasm_load_icu_data(ptr as unknown as VoidPtr);
        if (!result) {
            throw new Error("Failed to initialize ICU data");
        }
    } finally {
        _ems_.stackRestore(sp);
    }
}

export function installVfsFile(bytes: Uint8Array, asset: VfsAsset) {
    const virtualName: string = typeof (asset.virtualPath) === "string"
        ? asset.virtualPath
        : asset.name;
    const lastSlash = virtualName.lastIndexOf("/");
    let parentDirectory = (lastSlash > 0)
        ? virtualName.substring(0, lastSlash)
        : browserVirtualAppBase;
    let fileName = (lastSlash > 0)
        ? virtualName.substring(lastSlash + 1)
        : virtualName;
    if (fileName.startsWith("/")) {

View on GitHub (pinned to 290d5ab72c)

Solutions

  1. Verify the icudt.dat is the exact file shipped with this runtime build (match git hash / SDK version).
  2. Check the byte length/hash of the fetched buffer against the expected asset manifest entry; re-fetch if mismatched.
  3. Ensure the server is not double-compressing or mis-decompressing the .dat (Content-Encoding vs raw).
  4. If globalization is not needed, switch the runtime to invariant globalization mode to skip ICU loading entirely.

Example fix

// before: pointing loader at an old/standalone icudt.dat URL
config.resources.icudt = [{ url: '/old/icudt.dat' }];
// after: use the file from the matching runtime publish output
config.resources.icudt = publishAssets.icudt; // same build as dotnet.native.wasm
Defensive patterns

Strategy: validation

Validate before calling

// Validate the ICU bytes before loading
import { expectedIcuAssets } from './dotnet.runtime.config';
const expected = expectedIcuAssets.icudt?.[0];
if (!bytes || bytes.byteLength === 0) throw new Error('ICU bytes empty');
if (expected?.size && bytes.byteLength !== expected.size) {
  throw new Error(`ICU size mismatch: got ${bytes.byteLength}, expected ${expected.size}`);
}
loadIcuData(bytes);

Try / catch

try { loadIcuData(bytes); }
catch (e) {
  if (/Failed to initialize ICU data/.test(String(e.message))) {
    // surface a deployment hint: re-fetch the matching icudt.dat
    throw new Error('ICU load failed; verify the icudt.dat matches this runtime build.', { cause: e });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling loadIcuData(bytes) where _wasm_load_icu_data returns 0: corrupted or truncated ICU .dat, an ICU version that does not match this runtime build, an empty/wrong byte buffer, or WASM linear-memory exhaustion at posix_memalign/load time.

Common situations: Custom host fetching icudt.dat from a stale/old URL; partial publish where icudt.dat is truncated on disk; serving the file pre-gzipped without Content-Encoding so the runtime reads compressed bytes; mixing invariant-globalization build with full-ICU data file; CDN serving a partial chunk.

Related errors


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