denoland/deno · error · ERR_WASI_NOT_STARTED
ERR_WASI_NOT_STARTED
ERR_WASI_NOT_STARTED
Error message
wasi.start() has not been called
What it means
ERR_WASI_NOT_STARTED is thrown when a WASI import function needs the module's linear memory but none has been bound yet. Memory is captured in #getMemoryBuffer() from this.#memory, which is only set by start(), initialize(), or finalizeBindings(). If the wasm module calls any WASI function that touches memory (path_read, fd_write, args_get, ...) before one of those ran, this error surfaces.
Source
Thrown at ext/node/polyfills/wasi.ts:669
siFlags,
soDatalenPtr,
self.#getMemoryBuffer(),
);
},
sock_shutdown(fd: number, how: number) {
return ctx.sockShutdown(fd, how);
},
sock_accept(fd: number, flags: number, fdPtr: number) {
return ctx.sockAccept(fd, flags, fdPtr, self.#getMemoryBuffer());
},
};
}
#memory: WebAssembly.Memory | null = null;
#getMemoryBuffer(): Uint8Array {
if (!this.#memory) {
throw new ERR_WASI_NOT_STARTED();
}
// deno-lint-ignore deno-internal/prefer-primordials -- WebAssembly.Memory.prototype.buffer getter; no primordial equivalent
return new Uint8Array(this.#memory.buffer);
}
get wasiImport() {
return this.#wasiImport;
}
getImportObject() {
if (this.#version === "unstable") {
return { wasi_unstable: this.#wasiImport };
}
return { wasi_snapshot_preview1: this.#wasiImport };
}
start(instance?: WebAssembly.Instance): number {
if (this.#started) {View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Call `wasi.start(instance)` (command modules) or `wasi.initialize(instance)` (reactor modules) before invoking any exports or letting the module call WASI imports.
- Never call `instance.exports._start()` yourself; start() does that after binding memory.
- Keep instantiation and start in the same function so the ordering cannot be broken by refactoring.
Example fix
// before
const instance = new WebAssembly.Instance(module, { wasi_snapshot_preview1: wasi.wasiImport });
instance.exports._start(); // ERR_WASI_NOT_STARTED inside the first WASI call
// after
const instance = new WebAssembly.Instance(module, { wasi_snapshot_preview1: wasi.wasiImport });
wasi.start(instance); // binds memory, then invokes _start Defensive patterns
Strategy: validation
Validate before calling
// Enforce ordering: instantiate and start in one step.
function instantiateAndStart(
wasi: WASI,
module: WebAssembly.Module,
): WebAssembly.Instance {
const instance = new WebAssembly.Instance(module, wasi.getImportObject());
wasi.start(instance); // binds memory before _start runs
return instance;
} Try / catch
try {
wasi.start(instance);
} catch (err) {
if ((err as { code?: string }).code === 'ERR_WASI_NOT_STARTED') {
// memory never bound: lifecycle out of order
throw new Error('Call wasi.start(instance) before invoking exports');
}
throw err;
} Prevention
- Never call instance.exports._start() directly; always route through wasi.start().
- Keep new WebAssembly.Instance(...) and wasi.start(...) adjacent in the same function.
- Wrap the instantiate+start pair in one helper so ordering cannot drift.
When it happens
Trigger: Instantiating the module with `new WebAssembly.Instance(module, { wasi_snapshot_preview1: wasi.wasiImport })` and then calling `instance.exports._start()` directly instead of `wasi.start(instance)`; calling `wasi.getImportObject()` and letting the module run during instantiation (e.g. a start section that traps) before start() binds memory; invoking import functions manually from JS for testing.
Common situations: Wrapping instantiation in a helper that hides the wasi object so the caller forgets the start() step; porting code from a runtime where imports auto-attach memory; splitting instantiate/start across modules where ordering is not enforced.
Related errors
- ERR_WASI_ALREADY_STARTED
- ERR_INVALID_ARG_TYPE
- ERR_INVALID_ARG_VALUE
- ERR_HTTP_HEADERS_SENT
- ERR_CRYPTO_INVALID_STATE
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/c8322c5ea3078b23.
Report an issue: GitHub.