{"record":{"id":"68c0f93527bb933d","repo":"dotnet/runtime","slug":"async-continuation-was-not-preserved-by-the-link","errorCode":null,"errorMessage":"__async_continuation was not preserved by the linker or optimizer","messagePattern":"__async_continuation was not preserved by the linker or optimizer","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"src/native/libs/Common/JavaScript/host/assets.ts","lineNumber":127,"sourceCode":"// finishWebcilInstance are the R2R Webcil-in-Wasm host ABI defined by crossgen's WasmObjectWriter\n// (src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs, CreateDefaultGlobalImports/\n// WriteExports). Keep in sync with the corerun host\n// (src/coreclr/hosts/corerun/wasm/libCorerun.js, BrowserHost_ExternalAssemblyProbe). Unlike corerun,\n// which parses data segment 0 for payloadSize/tableSize, this loader receives them from boot config.\nfunction buildWebcilImports(memory: WebAssembly.Memory, payloadPtr: number, tableSize: number): Record<string, WebAssembly.ImportValue> {\n    const webcilImports: Record<string, WebAssembly.ImportValue> = { memory };\n    if (tableSize > 0) {\n        const stackPointer = _ems_.wasmExports?.__stack_pointer;\n        const rtlRestoreContextTag = _ems_.wasmExports?.__coreclr_wasm_rtlrestorecontext_tag;\n        const asyncContinuation = _ems_.wasmExports?.__async_continuation;\n        if (!stackPointer) {\n            throw new Error(\"__stack_pointer was not preserved by the linker or optimizer\");\n        }\n        if (!rtlRestoreContextTag) {\n            throw new Error(\"__coreclr_wasm_rtlrestorecontext_tag was not preserved by the linker or optimizer\");\n        }\n        if (!asyncContinuation) {\n            throw new Error(\"__async_continuation was not preserved by the linker or optimizer\");\n        }\n        const tableStartIndex = _ems_.wasmTable.length;\n        _ems_.wasmTable.grow(tableSize);\n        webcilImports.stackPointer = stackPointer;\n        webcilImports.rtlRestoreContextTag = rtlRestoreContextTag as unknown as WebAssembly.ImportValue;\n        webcilImports.asyncContinuation = asyncContinuation as unknown as WebAssembly.ImportValue;\n        webcilImports.table = _ems_.wasmTable;\n        webcilImports.tableBase = new WebAssembly.Global({ value: \"i32\", mutable: false }, tableStartIndex);\n        webcilImports.imageBase = new WebAssembly.Global({ value: \"i32\", mutable: false }, payloadPtr);\n    }\n    return webcilImports;\n}\n\n// Copies the payload into the allocated buffer, fills the R2R table (if any) and registers the\n// loaded image for BrowserHost_ExternalAssemblyProbe.\nfunction finishWebcilInstance(instance: WebAssembly.Instance, payloadPtr: number, payloadSize: number, tableSize: number, virtualPath: string): void {\n    const webcilVersion = (instance.exports.webcilVersion as WebAssembly.Global).value;\n    if (webcilVersion > 1 || webcilVersion < 0) {","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/dotnet/runtime/blob/60108ba66eb7d1d12f595480091b4ad80a24b172/src/native/libs/Common/JavaScript/host/assets.ts#L109-L145","documentation":"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.","triggerScenarios":"R2R webcil instantiation (tableSize > 0) where _ems_.wasmExports.__async_continuation is falsy, i.e. the runtime wasm module does not export it.","commonSituations":"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.","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."],"exampleFix":"# before: custom export list drops async continuation export\n\n# after\nemcc ... -s EXPORTED_FUNCTIONS=[...,__async_continuation,__stack_pointer]","handlingStrategy":"validation","validationCode":"function runtimeExportsAsyncContinuation(): boolean {\n  return !!((globalThis as any).Module?.wasmExports?.__async_continuation);\n}","typeGuard":"function hasAsyncContinuation(exp: any): exp is { __async_continuation: Function } {\n  return exp && !!exp.__async_continuation;\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["webcil","r2r","linker","async","build"],"backgroundTag":null,"analyzedSha":"60108ba66eb7d1d12f595480091b4ad80a24b172","analyzedAt":"2026-08-10T18:54:11.478Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}