Skip to content

std::thread::spawn unconditionally disabled on WASI breaks wasm32-wasip1-threads with emnapi's working pthread implementation #153475

@Brooooooklyn

Description

@Brooooooklyn

Summary

PR #151016 introduced a blanket cfg!(target_os = "wasi") guard in Thread::new() that immediately returns UNSUPPORTED_PLATFORM for all WASI targets, without ever calling pthread_create. This breaks projects targeting wasm32-wasip1-threads that link against emnapi, which provides a fully working pthread_create implementation backed by Web Workers.

Affected Code

library/std/src/sys/thread/unix.rs, lines 46-54:

impl Thread {
    pub unsafe fn new(stack: usize, init: Box<ThreadInit>) -> io::Result<Thread> {
        // FIXME: remove this block once wasi-sdk is updated with the fix from
        // https://github.com/WebAssembly/wasi-libc/pull/716
        // WASI does not support threading via pthreads. While wasi-libc provides
        // pthread stubs, pthread_create returns EAGAIN, which causes confusing
        // errors. We return UNSUPPORTED_PLATFORM directly instead.
        if cfg!(target_os = "wasi") {
            return Err(io::Error::UNSUPPORTED_PLATFORM);
        }

        // ... pthread_create call never reached for WASI ...

Background

PR #151016 was merged to fix a regression where wasi-libc's stub pthread_create returned EAGAIN, causing libraries like rayon to panic. The fix was correct for that specific scenario.

However, the wasm32-wasip1-threads target exists precisely for WASI programs that do support threading. Projects in the WebAssembly/Node.js ecosystem use emnapi (an implementation of Node-API for WebAssembly) which provides a real, working pthread_create that spawns Web Workers. This has been working reliably across the ecosystem until Rust 1.94.0.

The cfg!(target_os = "wasi") check is evaluated at compile time and cannot distinguish between:

  • wasi-libc's stub pthread_create (returns EAGAIN — broken)
  • emnapi's pthread_create (creates Web Workers — working)

Impact

napi-rs is a widely-used framework for building Node.js native addons in Rust, with support for compiling to wasm32-wasip1-threads for platform-independent WebAssembly distribution. It uses tokio's multi-thread runtime, which calls std::thread::spawn to create worker threads.

These projects are impacted.

Since Rust 1.94.0, all async functionality in napi-rs WASI builds is broken:

thread '<unnamed>' (2) panicked at
  tokio-1.50.0/src/runtime/scheduler/multi_thread/worker.rs:489:13:
OS can't spawn worker thread: operation not supported on this platform

This affects every napi-rs project that publishes a WASI target (used as a universal fallback when no prebuilt native binary is available for the user's platform).

Other projects using emnapi with wasm32-wasip1-threads are likely affected as well.

Reproduction

# Install the target
rustup target add wasm32-wasip1-threads

# Clone napi-rs
git clone https://github.com/napi-rs/napi-rs
cd napi-rs

# Install JS dependencies
yarn install --immutable --mode=skip-build

# Build the WASI example (requires emnapi to be available)
yarn build
RUSTFLAGS='--cfg tokio_unstable' \
  yarn workspace @examples/napi build --target wasm32-wasip1-threads --profile wasi

# Run tests with WASI binding forced
NAPI_RS_FORCE_WASI=true WASI_TEST=true SKIP_UNWIND_TEST=1 \
  yarn workspace @examples/napi test

With Rust 1.93.0: all tests pass.
With Rust 1.94.0: panics with "operation not supported on this platform" on any async operation.

Minimal analysis

The check if cfg!(target_os = "wasi") on line 52 of unix.rs compiles to a constant true for all WASI targets, including wasm32-wasip1-threads. The function returns Err(io::Error::UNSUPPORTED_PLATFORM) without ever attempting pthread_create. Since emnapi's pthread_create is linked into the final .wasm binary and works correctly, this early return is incorrect for this use case.

Versions

  • Rust 1.93.0: std::thread::spawn works on wasm32-wasip1-threads (calls pthread_create)
  • Rust 1.94.0: std::thread::spawn unconditionally returns UNSUPPORTED_PLATFORM on all WASI targets
  • Tokio: 1.44+ (any version — the issue is in std, not tokio)
  • emnapi: 1.7+

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-threadArea: `std::thread`C-bugCategory: This is a bug.I-prioritizeIssue: Indicates that prioritization has been requested for this issue.O-wasip1-threadsOperating system: *-wasmp1-threads, WASI Preview1 with atomics and threadsS-has-bisectionStatus: A bisection has been found for this issueT-libsRelevant to the library team, which will review and decide on the PR/issue.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions