Skip to content

nodejs{22,24}: fix libuv kqueue assertion crash on Darwin - #523674

Closed
mkg20001 wants to merge 85 commits into
NixOS:masterfrom
mkg20001:nodejs-kqueue-ebadf-fix
Closed

mkg20001 wants to merge 85 commits into
NixOS:masterfrom
mkg20001:nodejs-kqueue-ebadf-fix

Conversation

@mkg20001

Copy link
Copy Markdown
Member

Description

Fixes a SIGABRT (Abort trap: 6) crash in Node.js on Darwin (macOS) caused by libuv's kqueue poller asserting errno == EINTR after kevent() fails.

kevent() can also return EBADF (closed fd still in changelist) or ENOENT (fd removed between changelist submit and kevent call). This triggers most reliably with Node.js 24.15.0+ running pnpm with large package sets (1400+ packages) inside the Nix build sandbox, due to changes in ArrayBuffer transfer semantics (nodejs/node#61372) that alter file descriptor lifecycle timing.

The assertion (deps/uv/src/unix/kqueue.c:294) is present in all Node.js versions (22, 24, 26) since they all bundle libuv 1.51.0. The patch relaxes it to accept EBADF and ENOENT alongside EINTR — all transient conditions that the existing retry logic already handles correctly.

Root cause chain:

  1. Node.js 24.15.0 changed ArrayBuffer transfer behavior
  2. This alters how native addons (SQLite bindings in pnpm's store) manage memory/FD lifecycle
  3. An FD gets closed while still registered in kqueue's changelist
  4. kevent() returns EBADF instead of EINTR
  5. libuv's strict assert(errno == EINTR) fires → SIGABRT

Upstream references:

Things done

Admin and others added 15 commits May 16, 2026 17:55
Cherry-picks pkgs/development/compilers/rust/1_95.nix and the
rustPackages_1_95 wiring from staging-next 6534ba3, without
flipping the rust/rustPackages default away from 1_94 (which would
trigger a stdenv-wide rebuild).
Pinned to rustPackages_1_95 because oxc_transformer 0.129.0 uses
`if let` guards, which were not stabilized until Rust 1.95.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The v11 store index can contain a sideEffects map alongside the top-level files map, where each value is { added: Map<path, FileMetadata>, deleted?: string[] }. The previous fixup only zeroed checkedAt on top-level files, leaving sideEffects[*].added.checkedAt timestamps in the SQLite store, which caused fetchPnpmDeps tarballs to vary across builders for any package with native postinstall side effects.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The pnpm v11 store uses a SQLite database (index.db) whose binary format
is non-deterministic across platforms (page ordering, free lists differ).
This caused hash mismatches when building the same pnpmDeps on different
machines despite identical logical content.

Fix by dumping the SQLite database to a text SQL file during the fetch
phase and reconstructing it during the build phase. This ensures the
stored representation is fully deterministic.

Also fix broken `export` statements for pnpm_config_side_effects_cache
and pnpm_config_update_notifier which were missing `=` signs.
(cherry-picked from NixOS#521987)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
libuv's kqueue poller (`uv__io_poll` in `kqueue.c`) asserts that when
`kevent()` returns -1, `errno` must be `EINTR`. However, `kevent()` can
also return `EBADF` when a file descriptor is closed while still in the
kqueue changelist, or `ENOENT` when removed between changelist submit
and the kevent call.

This surfaces as an `Abort trap: 6` (SIGABRT) on Darwin when running
pnpm in the Nix build sandbox with Node.js 24.15.0+, due to changes in
ArrayBuffer transfer semantics that alter FD lifecycle timing.

The fix relaxes the assertion to accept EBADF and ENOENT in addition to
EINTR, all of which are transient conditions that the existing retry
logic already handles correctly.

Reproducer: `pnpm install --force` with 1400+ packages in nix sandbox.
Upstream: libuv/libuv#976

Assisted-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@mkg20001 mkg20001 closed this May 24, 2026
@mkg20001
mkg20001 deleted the nodejs-kqueue-ebadf-fix branch May 24, 2026 16:43

@nixpkgs-branch-check nixpkgs-branch-check Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR's base branch is set to master, but this PR causes 7964 rebuilds.
It is therefore considered a mass rebuild.
Please change the base branch to the right base branch for your changes (probably staging).

@nixpkgs-ci nixpkgs-ci Bot added 8.has: package (update) This PR updates a package to a newer version 2.status: merge conflict This PR has merge conflicts with the target branch 10.rebuild-linux: 501+ This PR causes many rebuilds on Linux and should normally target the staging branches. 10.rebuild-darwin: 501+ This PR causes many rebuilds on Darwin and should normally target the staging branches. 10.rebuild-linux: 501-1000 This PR causes many rebuilds on Linux and should normally target the staging branches. 10.rebuild-darwin: 5001+ This PR causes many rebuilds on Darwin and must target the staging branches. 10.rebuild-nixos-tests This PR causes rebuilds for all NixOS tests and should normally target the staging branches. 6.topic: python Python is a high-level, general-purpose programming language. 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: module (update) This PR changes an existing module in `nixos/` 6.topic: rust General-purpose programming language emphasizing performance, type safety, and concurrency. 6.topic: nodejs Node.js is a free, open-source, cross-platform JavaScript runtime environment labels May 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

2.status: merge conflict This PR has merge conflicts with the target branch 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 6.topic: nodejs Node.js is a free, open-source, cross-platform JavaScript runtime environment 6.topic: python Python is a high-level, general-purpose programming language. 6.topic: rust General-purpose programming language emphasizing performance, type safety, and concurrency. 8.has: module (update) This PR changes an existing module in `nixos/` 8.has: package (update) This PR updates a package to a newer version 10.rebuild-darwin: 501+ This PR causes many rebuilds on Darwin and should normally target the staging branches. 10.rebuild-darwin: 5001+ This PR causes many rebuilds on Darwin and must target the staging branches. 10.rebuild-linux: 501-1000 This PR causes many rebuilds on Linux and should normally target the staging branches. 10.rebuild-linux: 501+ This PR causes many rebuilds on Linux and should normally target the staging branches. 10.rebuild-nixos-tests This PR causes rebuilds for all NixOS tests and should normally target the staging branches.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants