nodejs / nodejs/node

worker_threads Worker exit aborts (SIGABRT) when a native addon (fsevents) has an in-flight napi_threadsafe_function — napi_release_threadsafe_function / uv_mutex_lock

オープン
#65,100 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

confirmed-bug node-api worker
主要言語
JavaScript
スター
122k
フォーク
37.3k
平均マージ
4日 2時間
マージ済み PR(30日)
283

説明

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

  1. npm install
  2. 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.

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

最小再現の main.mjs と worker.mjs から始めます。npm install と node main.mjs 50 を実行し、その後 v24.11.1 と v24.15.0 以降を比較します。stack に示されている worker の teardown パス、特に napi_release_threadsafe_function と Environment::RunCleanup を追跡します。50 個すべての worker が SIGABRT なしでコード 0 で終了すれば完了です。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
javascript, node.js
領域
backend, operating-systems
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
静か
明瞭さ
おおむね明確
初心者へのやさしさ
48/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。