Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

WasiProcess.run() never settles when instantiate fails or _start traps (e.g. missing fd_fdstat_set_rights import)

Open
#303 0 comments 0 reactions 1 assignee View on GitHub

Maintainers usually reply within 1 day

@dbaeumer is already working on this.

Since Oct 6, 2026.

Assessment

This issue has not been assessed yet.

Description

Summary

WasiProcess.run() never settles (no result, no rejection, no visible error) when the worker running the module throws before or while executing _start. Two ways this was observed:

  1. A module that imports wasi_snapshot_preview1.fd_fdstat_set_rights. The host does not implement it, so WebAssembly.instantiate throws a LinkError.
  2. A module whose _start traps (e.g. an unreachable instruction, which is what abort(), a failed assert, or std::terminate compile to).

Both hang process.run() forever. (1) is the missing import; (2) and (1) share the same root cause: errors in the main worker are only logged, never reported back to the extension host.

Impact

  • Any wasm program that imports fd_fdstat_set_rights hangs on launch with no diagnostic. We hit this in the wild: linking a C++ program with wasm-ld --no-gc-sections keeps every libc object, so the module imports the full wasi_snapshot_preview1 set (~45 functions) instead of the usual ~6, including fd_fdstat_set_rights. The program itself is fine (it builds and prints correctly under Node's node:wasi).
  • Any trapping program (abort(), failed assert, uncaught exception with -fno-exceptions, std::terminate, out-of-bounds access, stack overflow) leaves run() pending forever. Embedders such as terminals, test runners and build tools wait indefinitely and have no way to tell a hang from a long computation.
  • Because the error appears only in the worker's console, it is very hard to diagnose from the extension side.

Root cause (from reading the source at 6714478fe3b73855355403f40e70c0b950d0128e)

Missing import. fd_fdstat_set_rights does not appear anywhere under wasm-wasi-core/src (grep -rn set_rights wasm-wasi-core/src finds nothing). common/host.ts builds the import object with fd_fdstat_get and fd_fdstat_set_flags but no fd_fdstat_set_rights, so the property is undefined and instantiation fails with:

LinkError: WebAssembly.instantiate(): Import #0 "wasi_snapshot_preview1" "fd_fdstat_set_rights": function import requires a callable

I bisected this empirically: I generated one tiny module per wasi_snapshot_preview1 import used by the --no-gc-sections build (all of them), each importing exactly one function and exporting an empty _start, and ran each with createProcess(...).run() and a timeout. all others ran and exited with 0; only fd_fdstat_set_rights hung.

Swallowed error. In web/mainWorker.ts, handleMessage does await WebAssembly.instantiate(module, imports) and then calls _start with no try/catch. The exception rejects the promise returned by handleMessage, and the caller in web/connection.ts only does .catch(RAL().console.error). Meanwhile this._done is never resolved or rejected, so main() stays blocked on await connection.done() and never posts workerDone. On the extension-host side, run() only resolves on proc_exit or workerDone (common/process.ts / web/process.ts), and nothing listens for worker errors, so it waits forever.

web/threadWorker.ts has the same unguarded instantiate / wasi_thread_start path, so the same hang is expected for thread workers (I did not test threads).

Reproduction (no toolchain needed)

Module (WAT):

(module
  (import "wasi_snapshot_preview1" "fd_fdstat_set_rights" (func))
  (memory (export "memory") 1)
  (func (export "_start")))

(Signature is irrelevant for the repro; the real import is (i32 i64 i64) -> i32. A host function type mismatch is not checked for JS-provided imports, and the missing property is what fails.)

From a VS Code web extension with ms-vscode.wasm-wasi-core installed:

import { Wasm } from '@vscode/wasm-wasi';

const wasm = await Wasm.load();
const module = await WebAssembly.compile(bytes); // the module above
const process = await wasm.createProcess('t', module, { stdio: { out: { kind: 'pipeOut' }, err: { kind: 'pipeOut' } } });
await process.run(); // never resolves or rejects

Trap variant: replace the body with (module (memory (export "memory") 1) (func (export "_start") unreachable)); run() also never settles.

Real-world trigger: compile a hello-world with a wasm32-wasip1 clang, then link with wasm-ld ... --no-gc-sections. The resulting module imports fd_fdstat_set_rights (plus sock_accept, fd_advise, ...); it runs fine under Node's node:wasi.

Tested with wasm-wasi-core 1.0.2 (as loaded by @vscode/test-web in Chromium), source at the commit above.

Suggested fix

  1. Add fd_fdstat_set_rights to the host and service layers, returning Errno.nosys (it is part of wasi_snapshot_preview1; a no-op/nosys stub is enough for programs that merely import it).
  2. In mainWorker.ts (and threadWorker.ts), wrap instantiate and _start in try/catch; on failure post an error message back (or at least still resolve _done so workerDone is posted) so that run() rejects or returns a non-zero exit code instead of hanging. For a trap, a conventional exit code with the error written to stderr would match what other WASI hosts do.

Disclosure

This issue was detected, root-caused and written up by Claude (an AI coding assistant, Claude Code) while working in a user's repository, and is filed by Claude with the explicit consent of the repository owner (Ambeco). The reproduction and the bisect were run for real in Chromium via @vscode/test-web; the root-cause analysis comes from reading the source, and the hang mechanism was not additionally confirmed with instrumentation inside the worker.

Dominant language
TypeScript
Stars
456
Forks
42
Avg merge
1d 3h
Merged PRs (30d)
11

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from microsoft/vscode-wasm

All issues in microsoft/vscode-wasm

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.