dotnet/runtime · critical · Error

__coreclr_wasm_rtlrestorecontext_tag was not preserved by th

Error message

__coreclr_wasm_rtlrestorecontext_tag was not preserved by the linker or optimizer

What it means

Thrown by buildWebcilImports() (src/native/libs/Common/JavaScript/host/assets.ts:114) for an R2R webcil asset. The RTL restore-context tag (__coreclr_wasm_rtlrestorecontext_tag) is the wasm exception/tag export used by R2R images to restore execution context during exception handling; if it is missing from wasmExports, the R2R import set is incomplete and the host refuses to continue.

Source

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

// Builds the `webcil` import object. For R2R images (tableSize > 0) the module imports the runtime's
// stack pointer, exception tag, indirect-call table and base globals; this also grows the table.
// These import names and the webcilVersion/getWebcilPayload/fillWebcilTable handshake in
// finishWebcilInstance are the R2R Webcil-in-Wasm host ABI defined by crossgen's WasmObjectWriter
// (src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs, CreateDefaultGlobalImports/
// WriteExports). Keep in sync with the corerun host
// (src/coreclr/hosts/corerun/wasm/libCorerun.js, BrowserHost_ExternalAssemblyProbe). Unlike corerun,
// which parses data segment 0 for payloadSize/tableSize, this loader receives them from boot config.
function buildWebcilImports(memory: WebAssembly.Memory, payloadPtr: number, tableSize: number): Record<string, WebAssembly.ImportValue> {
    const webcilImports: Record<string, WebAssembly.ImportValue> = { memory };
    if (tableSize > 0) {
        const stackPointer = _ems_.wasmExports?.__stack_pointer;
        const rtlRestoreContextTag = _ems_.wasmExports?.__coreclr_wasm_rtlrestorecontext_tag;
        const asyncContinuation = _ems_.wasmExports?.__async_continuation;
        if (!stackPointer) {
            throw new Error("__stack_pointer was not preserved by the linker or optimizer");
        }
        if (!rtlRestoreContextTag) {
            throw new Error("__coreclr_wasm_rtlrestorecontext_tag was not preserved by the linker or optimizer");
        }
        if (!asyncContinuation) {
            throw new Error("__async_continuation was not preserved by the linker or optimizer");
        }
        const tableStartIndex = _ems_.wasmTable.length;
        _ems_.wasmTable.grow(tableSize);
        webcilImports.stackPointer = stackPointer;
        webcilImports.rtlRestoreContextTag = rtlRestoreContextTag as unknown as WebAssembly.ImportValue;
        webcilImports.asyncContinuation = asyncContinuation as unknown as WebAssembly.ImportValue;
        webcilImports.table = _ems_.wasmTable;
        webcilImports.tableBase = new WebAssembly.Global({ value: "i32", mutable: false }, tableStartIndex);
        webcilImports.imageBase = new WebAssembly.Global({ value: "i32", mutable: false }, payloadPtr);
    }
    return webcilImports;
}

// Copies the payload into the allocated buffer, fills the R2R table (if any) and registers the
// loaded image for BrowserHost_ExternalAssemblyProbe.

View on GitHub (pinned to 60108ba66e)

Solutions

  1. Rebuild the runtime with the default build that preserves __coreclr_wasm_rtlrestorecontext_tag.
  2. Match the R2R assembly toolchain version to the runtime version so the export set agrees.
  3. When customizing the build, explicitly export the tag in the linker configuration.

Example fix

# before: export list omits the tag -> 'was not preserved by the linker or optimizer'

# after
emcc ... -s EXPORTED_FUNCTIONS=[...,__coreclr_wasm_rtlrestorecontext_tag,...]
Defensive patterns

Strategy: validation

Validate before calling

function runtimeExportsRtlTag(): boolean {
  return !!((globalThis as any).Module?.wasmExports?.__coreclr_wasm_rtlrestorecontext_tag);
}

Type guard

function hasRtlRestoreTag(exp: any): exp is { __coreclr_wasm_rtlrestorecontext_tag: WebAssembly.Global } {
  return exp && !!exp.__coreclr_wasm_rtlrestorecontext_tag;
}

Prevention

When it happens

Trigger: R2R webcil instantiation (tableSize > 0) where _ems_.wasmExports.__coreclr_wasm_rtlrestorecontext_tag is falsy. The runtime wasm module was linked without preserving this export.

Common situations: Custom linker/optimizer configuration stripping exception/tag exports; runtime built without the R2R host-ABI exports; mismatch between an R2R assembly's expected ABI and the runtime that loads it.

Related errors


AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10). Data as JSON: /api/errors/41b4cc4346396bd5. Report an issue: GitHub.