Version
v24.15.0 through v24.19.0 (tested v24.15.0, v24.16.0, v24.19.0 — all crash).
Does NOT reproduce on v24.11.0 or v24.11.1.
Platform
macOS 15.6.1 (24G90), Apple Silicon (arm64)
Subsystem
worker_threads, N-API (napi_threadsafe_function)
What steps will reproduce the bug?
Minimal repro repo: https://github.com/mastoj/node24-fsevents-worker-threads-abort
npm install
node main.mjs 50
main.mjs spawns 50 worker_threads.Workers sequentially. Each worker
(worker.mjs) does:
import { createRequire } from "node:module";
const require = createRequire(import.meta.url);
const fsevents = require("fsevents");
fsevents.watch(process.argv[2], () => {});
setTimeout(() => process.exit(0), 5);
i.e. it starts a native fsevents watch (which registers a
napi_threadsafe_function under the hood) and exits the worker shortly
after, without explicitly stopping the watcher first.
How often does it reproduce? Is there a required condition?
100% reproducible on Node.js v24.15.0+ on macOS. Crashes on the very first
worker. 0% reproducible on Node.js v24.11.0/v24.11.1 (ran 50 workers cleanly).
What is the expected behavior?
All workers start, watch, and exit cleanly with code 0:
worker 0 exited with code 0
...
worker 49 exited with code 0
done, no crash across 50 workers
(This is what actually happens on v24.11.0.)
What do you see instead?
The whole process aborts with SIGABRT (exit code 134) on the very first
worker — before any of the console.log lines are even printed, since the
abort takes down the entire process (all worker threads share one OS
process).
$ node main.mjs 50
Abort trap: 6
$ echo $?
134
macOS crash reporter consistently shows the same stack trace on the
"WorkerThread":
__pthread_kill
pthread_kill
abort
uv_mutex_lock
napi_release_threadsafe_function
fse_instance_destroy
napi_env__::CallIntoModule<...>
node_napi_env__::CallFinalizer(void (*)(napi_env__*, void*, void*), void*, void*)
v8impl::Reference::Finalize()
node_napi_env__::DeleteMe()
node::Environment::CloseHandle<...>
uv_run
node::Environment::RunCleanup()
node::FreeEnvironment(node::Environment*)
node::worker::Worker::Run()
node::worker::Worker::StartThread(...)::$_0::__invoke(void*)
_pthread_start
thread_start
i.e. during worker-thread Environment teardown, napi_release_threadsafe_function
attempts uv_mutex_lock while finalizing fsevents' native threadsafe
function, and this ends in abort() instead of a clean/graceful teardown.
Additional context
This was originally found as a crash inside a real-world Next.js 16.3.0
monorepo build (next build --turbopack), where Next's build worker threads
transitively load fsevents (via chokidar/watchpack) and exit shortly
after doing their work. The exact same crash signature (same stack trace)
was observed across 15+ independent crash reports collected via macOS's
crash reporter during real builds, before being reduced to this minimal,
Next.js-free, fsevents-only reproduction.
It doesn't reproduce in a fresh create-next-app project (which doesn't
happen to have an active fsevents watcher inside its build workers) —
only projects where a native addon with an in-flight
napi_threadsafe_function is active in a worker thread at worker-exit
time.
Version
v24.15.0 through v24.19.0 (tested v24.15.0, v24.16.0, v24.19.0 — all crash).
Does NOT reproduce on v24.11.0 or v24.11.1.
Platform
macOS 15.6.1 (24G90), Apple Silicon (arm64)
Subsystem
worker_threads, N-API (napi_threadsafe_function)
What steps will reproduce the bug?
Minimal repro repo: https://github.com/mastoj/node24-fsevents-worker-threads-abort
npm installnode main.mjs 50main.mjsspawns 50worker_threads.Workers sequentially. Each worker(
worker.mjs) does:i.e. it starts a native
fseventswatch (which registers anapi_threadsafe_functionunder the hood) and exits the worker shortlyafter, without explicitly stopping the watcher first.
How often does it reproduce? Is there a required condition?
100% reproducible on Node.js v24.15.0+ on macOS. Crashes on the very first
worker. 0% reproducible on Node.js v24.11.0/v24.11.1 (ran 50 workers cleanly).
What is the expected behavior?
All workers start, watch, and exit cleanly with code 0:
(This is what actually happens on v24.11.0.)
What do you see instead?
The whole process aborts with SIGABRT (exit code 134) on the very first
worker — before any of the
console.loglines are even printed, since theabort takes down the entire process (all worker threads share one OS
process).
macOS crash reporter consistently shows the same stack trace on the
"WorkerThread":
i.e. during worker-thread
Environmentteardown,napi_release_threadsafe_functionattempts
uv_mutex_lockwhile finalizingfsevents' native threadsafefunction, and this ends in
abort()instead of a clean/graceful teardown.Additional context
This was originally found as a crash inside a real-world Next.js 16.3.0
monorepo build (
next build --turbopack), where Next's build worker threadstransitively load
fsevents(viachokidar/watchpack) and exit shortlyafter doing their work. The exact same crash signature (same stack trace)
was observed across 15+ independent crash reports collected via macOS's
crash reporter during real builds, before being reduced to this minimal,
Next.js-free,
fsevents-only reproduction.It doesn't reproduce in a fresh
create-next-appproject (which doesn'thappen to have an active
fseventswatcher inside its build workers) —only projects where a native addon with an in-flight
napi_threadsafe_functionis active in a worker thread at worker-exittime.