Skip to content

fix(cleanup): run pnpm scripts on Node 24.22 so next dev loads Next once - #300

Merged
ngducn merged 4 commits into
mainfrom
esta/fix-292-request-scope
Oct 24, 2026
Merged

ngducn merged 4 commits into
mainfrom
esta/fix-292-request-scope

Conversation

@ngducn

@ngducn ngducn commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner

On a local pnpm dev server, the bill's receipt picture, the report downloads and the document view sometimes answered a server error, and that failed north-star step 4 about one run in three. Mẹ never saw it: production and CI were never affected. The cause is the Node version this Mac runs, not Esta's code.

One thing to know, no action needed: every pnpm command now runs on Node 24.22.0, which pnpm downloads once and keeps beside the dependencies. It no longer uses the Node on PATH, which is 25.9.0 on this Mac. I recommend keeping it this way. The alternative is to install Node 24.21 or later on the Mac by hand, and the same bug comes back whenever someone runs a different Node.

Why

Node before 24.21.0 (and the whole 25 line) stops resolving symlinks in require once anything in the process has stat-ed a pipe or a socket. Node fixed this upstream in nodejs/node#65113. pnpm reaches Next through a symlink, so under next dev a second copy of Next loaded with its own empty request store. Every route handler loaded after that copy failed with "cookies was called outside a request scope". Production builds were not affected, and CI already ran Node 24.22.

What changed

  • devEngines.runtime in package.json and .nvmrc pin Node 24.22.0. pnpm runs every script on it, and the verify launcher starts the web server with the same binary.
  • The phase north-star rows serve the production build, as CI does (ESTA_E2E_SERVER=build).
  • A test checks that the running Node resolves Next to one real path after a pipe stat, and that it is the pinned Node.

Scope

Tradeoffs

  • A version guard in scripts/web.ts would also catch a stray node scripts/web.ts. I left it out, because pnpm and the verify launcher both use the pinned Node now.

Verification

  • North-star on next dev, slot 3: 9 of 29 runs failed step 4 on Node 25.9.0. On Node 24.22.0, 0 of 20 failed: 10 runs with it first on PATH and 10 through the pin, with the server confirmed on v24.22.0.
  • scripts/node-runtime.test.ts fails on 25.9.0, where require returns apps/web/node_modules/next/..., and passes through pnpm on 24.22.0.
  • Through heavy.sh: pnpm check passes, the receipts spec passes 5 of 5, and the phase 4 north-star row passes on a fresh production build.
Details
  • How the cause was found: a passive Module.prototype._compile tracer showed that in failing runs only, the server process evaluates work-unit-async-storage.external.js twice. The second copy is loaded through the symlink path (middleware.js → setup-node-env.external.js → node-environment → patch-error-inspect). A seven-line script reproduces the bug outside Next: resolve once, fstatSync a pipe, resolve again.
  • Load and HMR were ruled out first. 450 receipt requests at concurrency 8 mixed with page renders all answered 200, and so did HMR edits of member.ts.
  • Logs: /tmp/owner-fix292/ns-rate-*.log, ns-trace*-*.log, ns-node24-*.log, ns-fixed-*.log. Tracers: /tmp/owner-fix292/probe/.

🤖 Generated with Claude Code

t and others added 4 commits October 24, 2026 17:36
…, as CI does

A failure only next dev shows can no longer fail a phase exit (#292).
PhaseCheck rows take an env that every command of the row inherits.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Fails on Node 25.9.0, the Node on PATH here: after any pipe or socket
stat, require returns the pnpm symlink path and next dev loads a second
copy of Next (#292, #127).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…s Next once

Node before 24.21.0 stops resolving symlinks in require once the process
has stat-ed a pipe or a socket (nodejs/node#65113). Through pnpm's
apps/web/node_modules/next link, next dev then loaded a second copy of
Next, whose request store is always empty, and route handlers failed
with cookies outside a request scope. devEngines.runtime makes pnpm
download the pinned Node and run every script on it, whatever node is on
PATH; the verify launcher uses the same binary.

Closes #292
Closes #127

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@ngducn
ngducn force-pushed the esta/fix-292-request-scope branch from ca9e72d to 32b59ac Compare October 24, 2026 10:40
@ngducn
ngducn merged commit 8cd7cec into main Oct 24, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[low] The bill's receipt picture sometimes fails under pnpm dev, which fails north-star step 4

1 participant