dotnet/runtime · error · Error
cwrap ${name} not found or not a function
Error message
cwrap ${name} not found or not a function What it means
Thrown by the internal `cwrap` helper in the .NET wasm runtime when it cannot resolve a C export by name. The helper first tries a fast path reading `Module.wasmExports[name]`, then falls back to emscripten's `Module.cwrap`; if neither yields a function, the runtime cannot expose the native interop binding and aborts. This almost always indicates the wasm module was stripped of an expected export or `init_c_exports` ran before the wasm module finished instantiating.
Source
Thrown at src/mono/browser/runtime/cwraps.ts:308
// Module["wasmExports"] may not be defined yet if we are early enough in the startup process
// in that case, we need to rely on emscripten's lazy wrappers
Module["wasmExports"]
? <Function>((<any>Module["wasmExports"])[name])
: undefined;
// If the argument count for the wasm function doesn't match the signature, fall back to cwrap
if (fce && argTypes && (fce.length !== argTypes.length)) {
mono_log_error(`argument count mismatch for cwrap ${name}`);
fce = undefined;
}
// We either failed to find the raw wasm func or for some reason we can't use it directly
if (typeof (fce) !== "function")
fce = Module.cwrap(name, returnType, argTypes, opts);
if (typeof (fce) !== "function") {
const msg = `cwrap ${name} not found or not a function`;
throw new Error(msg);
}
return fce;
}
export function init_c_exports (): void {
const fns = [...fn_signatures];
for (const sig of fns) {
const wf: any = wrapped_c_functions;
const [lazyOrSkip, name, returnType, argTypes, opts] = sig;
const maybeSkip = typeof lazyOrSkip === "function";
if (lazyOrSkip === true || maybeSkip) {
// lazy init on first run
wf[name] = function (...args: any[]) {
const isNotSkipped = !maybeSkip || !lazyOrSkip();
mono_assert(isNotSkipped, () => `cwrap ${name} should not be called when binding was skipped`);
const fce = cwrap(name, returnType, argTypes, opts);
wf[name] = fce;
return fce(...args);View on GitHub (pinned to 60108ba66e)
Solutions
- Re-deploy the matching pair of `dotnet.runtime.js` and `dotnet.native.wasm` from one publish output.
- Defer any runtime API calls until after `dotnet.createDotnetRuntime` resolves (the `onRuntimeInitialized` / module.ready promise).
- If you customised emscripten export flags, ensure `-s EXPORTED_FUNCTIONS` (or `EXPORT_KEEPALIVE`) includes the missing native symbol; check the name printed in the error.
- Rebuild with `--verbosity detailed` and inspect the linker output to confirm the export survives.
Example fix
// before: calling a binding before runtime ready const r = cwraps.mono_wasm_add_assembly(...); // throws 'cwrap mono_wasm_add_assembly not found' // after: wait for the runtime module promise await dotnet.createDotnetRuntime(opts); const r = cwraps.mono_wasm_add_assembly(...);
Defensive patterns
Strategy: validation
Validate before calling
function isExportAvailable (name) {
const m = Module.wasmExports || {};
return typeof m[name] === 'function';
}
// guard before use:
if (!isExportAvailable('mono_wasm_add_assembly')) { /* await runtimeReadyPromise */ } Type guard
function isWasmReady (): boolean {
return !!Module.wasmExports && typeof Module.cwrap === 'function';
} Try / catch
try {
return cwraps.mono_wasm_add_assembly(name, ptr, len);
} catch (e) {
if (e instanceof Error && /cwrap .* not found/.test(e.message)) {
throw new Error(`Runtime binding missing; ensure the runtime module finished loading and that dotnet.runtime.js matches dotnet.native.wasm. Cause: ${e.message}`);
}
throw e;
} Prevention
- Always `await dotnet.createDotnetRuntime(opts)` (or the module.ready promise) before touching any wrapped export.
- Ship `dotnet.runtime.js` and `dotnet.native.wasm` from the same publish output.
- If customising emscripten exports, keep the .NET required exports on the EXPORTED_FUNCTIONS list.
When it happens
Trigger: Triggered from `init_c_exports` (or its lazy per-call wrapper at cwraps.ts:321-327) when iterating `fn_signatures` and binding each name. A name is missing because (a) the linker/emscripten dead-code-elimination removed the export, (b) the loaded `dotnet.native.wasm` is from a different build than `dotnet.runtime.js`, or (c) `Module.wasmExports` is still undefined and emscripten's lazy wrapper also returns nothing.
Common situations: Using a custom emscripten link step that strips exports; partial deploy where `dotnet.native.wasm` and `dotnet.runtime.js` come from different SDK builds; calling a wrapped export very early in startup before `onRuntimeInitialized`; running against an AOT/interpreter wasm build that omitted a particular native export.
Related errors
- Expected ${shortName} to be a function
- Unrecognized asset behavior:${asset.behavior}, for asset ${a
- Native module already loaded
- Module.ready couldn't be redefined.
- .NET runtime has failed to start, because too much memory wa
AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10).
Data as JSON: /api/errors/fbeefe5d8e3e98ed.
Report an issue: GitHub.