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

  1. Call `wasi.start(instance)` (command modules) or `wasi.initialize(instance)` (reactor modules) before invoking any exports or letting the module call WASI imports.
  2. Never call `instance.exports._start()` yourself; start() does that after binding memory.
  3. 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

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


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/c8322c5ea3078b23. Report an issue: GitHub.