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
Summary
PR #151016 introduced a blanket
cfg!(target_os = "wasi")guard inThread::new()that immediately returnsUNSUPPORTED_PLATFORMfor all WASI targets, without ever callingpthread_create. This breaks projects targetingwasm32-wasip1-threadsthat link against emnapi, which provides a fully workingpthread_createimplementation backed by Web Workers.Affected Code
library/std/src/sys/thread/unix.rs, lines 46-54:Background
PR #151016 was merged to fix a regression where wasi-libc's stub
pthread_createreturnedEAGAIN, causing libraries like rayon to panic. The fix was correct for that specific scenario.However, the
wasm32-wasip1-threadstarget 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, workingpthread_createthat 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:pthread_create(returnsEAGAIN— broken)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-threadsfor platform-independent WebAssembly distribution. It uses tokio's multi-thread runtime, which callsstd::thread::spawnto create worker threads.These projects are impacted.
Since Rust 1.94.0, all async functionality in napi-rs WASI builds is broken:
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-threadsare likely affected as well.Reproduction
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 ofunix.rscompiles to a constanttruefor all WASI targets, includingwasm32-wasip1-threads. The function returnsErr(io::Error::UNSUPPORTED_PLATFORM)without ever attemptingpthread_create. Since emnapi'spthread_createis linked into the final.wasmbinary and works correctly, this early return is incorrect for this use case.Versions
std::thread::spawnworks onwasm32-wasip1-threads(callspthread_create)std::thread::spawnunconditionally returnsUNSUPPORTED_PLATFORMon all WASI targetsReferences
unix.rscode on WASI targets #147572pthread_createstub's error code WebAssembly/wasi-libc#716