dotnet/runtime · critical · Error
__async_continuation was not preserved by the linker or opti
Error message
__async_continuation 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. __async_continuation is the runtime export R2R images call to resume an async method; if it is missing from _ems_.wasmExports the R2R import object cannot be completed and async resumption would break, so the host throws.
Source
Thrown at src/native/libs/Common/JavaScript/host/assets.ts:127
// 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.
function finishWebcilInstance(instance: WebAssembly.Instance, payloadPtr: number, payloadSize: number, tableSize: number, virtualPath: string): void {
const webcilVersion = (instance.exports.webcilVersion as WebAssembly.Global).value;
if (webcilVersion > 1 || webcilVersion < 0) {View on GitHub (pinned to 60108ba66e)
Solutions
- Rebuild the runtime with the default configuration that keeps __async_continuation exported.
- Align the R2R assembly toolchain and runtime versions.
- Add __async_continuation to the linker --export list when customizing the build.
Example fix
# before: custom export list drops async continuation export # after emcc ... -s EXPORTED_FUNCTIONS=[...,__async_continuation,__stack_pointer]
Defensive patterns
Strategy: validation
Validate before calling
function runtimeExportsAsyncContinuation(): boolean {
return !!((globalThis as any).Module?.wasmExports?.__async_continuation);
} Type guard
function hasAsyncContinuation(exp: any): exp is { __async_continuation: Function } {
return exp && !!exp.__async_continuation;
} Prevention
- Build the runtime with the default export set that keeps __async_continuation.
- Do not let an aggressive optimizer strip async-resume exports.
- Match runtime and R2R toolchain versions.
When it happens
Trigger: R2R webcil instantiation (tableSize > 0) where _ems_.wasmExports.__async_continuation is falsy, i.e. the runtime wasm module does not export it.
Common situations: Linker/optimizer stripped __async_continuation from the runtime exports; runtime built from a source tree that renamed or removed the export; version skew between the R2R assembly producer and the runtime.
Related errors
- __stack_pointer was not preserved by the linker or optimizer
- __coreclr_wasm_rtlrestorecontext_tag was not preserved by th
- Unsupported Webcil version: ${webcilVersion}
- Unsupported Webcil version: ${webcilVersion}
- cwrap ${name} not found or not a function
AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10).
Data as JSON: /api/errors/68c0f93527bb933d.
Report an issue: GitHub.