Repository navigation
v8: Node 26.9.0 crashes with Check failed: new_capacity > 0. when Error.stackTraceLimit is set above 357913941 with --trace-uncaught #66074
Description
Activity
Reproduced on v26.9.0 and local main at 99f0dde (macOS x64) with --trace-uncaught.
@silverwind Could you add that flag to the repro command? It doesn't crash without it in my environment.
You are right, this requires the flag to crash which I had set in NODE_OPTIONS, updated. Minimal reproduction is now this and I reproduced this on Linux too.
node --trace-uncaught -e 'Error.stackTraceLimit=Infinity; Error()'
@inoway46 I’d like to work on fixing this. Before I start, should the fix be made directly in nodejs/node under deps/v8, or should this be addressed upstream in v8/v8 first and then backported to Node.js?
I’d also be happy to add a regression test covering the Error.stackTraceLimit overflow case.
I'm working on an upstream fix in V8 for the underlying stack trace limit overflow.
Following @richardlau guidance, I'll work on getting the fix into V8 first, and then it can be backported to Node.js if appropriate.
I'll update this issue once there's progress on the V8 side.
The upstream V8 fix is now uploaded for review:
https://chromium-review.googlesource.com/c/v8/v8/+/8426465
It fixes the overflow by comparing Error.stackTraceLimit in frames before converting it to raw CallSiteInfo slots, and adds a regression test covering the large-limit cases and Infinity.
The CL has passed upload presubmit and is currently awaiting V8 review. Once it lands upstream, the fix can be considered for backport to Node.js.
Confirmed on Windows 11 x64 (10.0.26100). This also affects an attached Inspector session, without --trace-uncaught.
Version comparison
| Reproduction | v26.8.1 | v26.9.0 |
|---|---|---|
Error.stackTraceLimit = Infinity; new Error() without debugging |
Exit 0 | Exit 0 |
Same expression with --trace-uncaught |
Exit 0 | Exit 2147483651 |
| Same expression with an external Inspector client attached as below | Exit 0 | Exit 2147483651 |
The failing cases print:
# Fatal error in , line 0
# Check failed: new_capacity > 0.
The Windows exit code is 0x80000003.
Inspector reproduction, no third-party dependencies
Start the target:
node --inspect-brk=127.0.0.1:0 -e 'Error.stackTraceLimit=Infinity;new Error();console.log("OK")'Connect an external Chrome DevTools Protocol client to the WebSocket URL printed on stderr. Send these commands in order, waiting for each response:
{"id":1,"method":"Runtime.enable"}
{"id":2,"method":"Debugger.enable"}
{"id":3,"method":"Runtime.runIfWaitingForDebugger"}When Debugger.paused is received, send:
{"id":4,"method":"Debugger.resume"}On v26.9.0 the target crashes with the assertion above. On v26.8.1 it prints OK; disconnect the client to let the target exit. Both NODE_OPTIONS and VSCODE_INSPECTOR_OPTIONS were removed from the target environment for these comparisons.
This was initially encountered while debugging an electron-vite application in VS Code. Importing unplugin-vue-components/vite (32.0.0) under an attached debugger also reproduced it outside VS Code. Reducing the reproduction to the expression above removes Electron, VS Code, and all npm dependencies from the required setup.
The external Inspector detail matters: a same-thread node:inspector Session with only Debugger.enable did not reproduce the crash in a separate test.
V8 asked for a tracking bug before review, so I've filed one:
https://issues.chromium.org/issues/565047704
The CL (8426465) now carries the Bug: line and links back to this issue.
Root cause, for the record: Error.stackTraceLimit counts frames, but since crrev.com/c/7673818 the raw call site data stores CallSiteInfo::Fields::kCount slots per frame. CaptureAndSetErrorStack multiplies the limit by kCount before comparing it against the array length, and that product overflows for large limits. Node's V8 14.6 backport has kCount == 6 with signed arithmetic, so INT_MAX * 6 wraps negative and trips Check failed: new_capacity > 0.. On current V8 main the same expression wraps in uint32_t instead, which silently drops frames from error.stack rather than crashing. The fix compares against the frame count (length / kCount) so the multiplication only happens once it is known to be bounded.
@17630966776 — your Inspector finding is consistent with this and isn't a separate bug. The trim path runs whenever capture-for-uncaught-exceptions is enabled, and an attached Inspector session turns that on just as --trace-uncaught does.
The CL is awaiting V8 review. I'll update here once it lands and backport becomes relevant.
The upstream V8 fix has landed:
- CL: https://chromium-review.googlesource.com/c/v8/v8/+/8426465
- Commit: v8/v8@786c1c2 —
[stack-traces] Fix overflow in Error.stackTraceLimit trimming
It compares Error.stackTraceLimit in frames before converting it to raw CallSiteInfo slots, and adds a cctest regression test covering the large-limit values and Infinity.
One practical note: it landed on V8 main, which is currently at 15.6, while deps/v8 here is at 14.6.202.34. So this won't reach Node through the regular V8 update path for a long while, and the reported crash stays reproducible until then.
@richardlau — following your earlier pointer to maintaining-V8.md, would a floating patch onto deps/v8 be welcome here, or would you rather wait for the next V8 upgrade? I'm happy to open the PR via git node v8 backport 8426465 if that's the preferred route.
Version
v26.9.0
Platform
Subsystem
v8
What steps will reproduce the bug?
How often does it reproduce? Is there a required condition?
Every time
What is the expected behavior? Why is that the expected behavior?
No crash
What do you see instead?
Additional information
Any stack trace limit above 357913941 (2^32 / 12) triggers the crash. v26.8.2 does not crash. Requires
--trace-uncaughtto crash.Likely culprit is #65764
Popular module triggering the crash: https://github.com/wooorm/import-meta-resolve/blob/4.2.0/lib/errors.js#L427-L436