Repository navigation
Fatal Error in V8 Debugging Context on Node.js v23.7.0 #57606
Description
Version
23.7.0
Platform
Darwin Apples-MacBook-Pro.local 24.3.0 Darwin Kernel Version 24.3.0: Thu Jan 2 20:24:16 PST 2025; root:xnu-11215.81.4~3/RELEASE_ARM64_T6000 arm64
Subsystem
No response
What steps will reproduce the bug?
- Run a script that involves debugging, breakpoints, or function scope evaluation
- Observe the crash with the fatal error
How often does it reproduce? Is there a required condition?
The issue reproduces consistently when running a script that involves debugging, particularly with breakpoints, function scope evaluation, or closures.
What is the expected behavior? Why is that the expected behavior?
The debugger should pause execution at the debugger; statement and allow the user to inspect variables within the function's scope without causing a crash or becoming unresponsive.
What do you see instead?
I encountered a fatal error while running Node.js v23.7.0, leading to a crash with the following message:
Fatal error in , line 0
Check failed: needs_context && current_scope_ == closure_scope_ && current_scope_->is_function_scope() && !function_.is_null() implies function_->context() != *context_.
Additional information
Complete Error log trace if required
Fatal error in , line 0
Check failed: needs_context && current_scope_ == closure_scope_ && current_scope_->is_function_scope() && !function_.is_null() implies function_->context() != *context_.
#FailureMessage Object: 0x16bc90698
----- Native stack trace -----
1: 0x1044899ac node::NodePlatform::GetStackTracePrinter()::$_0::__invoke() [/opt/homebrew/Cellar/node/23.6.1/bin/node]
2: 0x104f00f88 V8_Fatal(char const*, ...) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
3: 0x1046b264c v8::internal::ScopeIterator::start_position() [/opt/homebrew/Cellar/node/23.6.1/bin/node]
4: 0x1046b2fec v8::internal::ScopeIterator::VisitLocalScope(std::__1::function<bool (v8::internal::Handlev8::internal::String, v8::internal::Handlev8::internal::Object, v8::internal::ScopeIterator::ScopeType)> const&, v8::internal::ScopeIterator::Mode, v8::internal::ScopeIterator::ScopeType) const [/opt/homebrew/Cellar/node/23.6.1/bin/node]
5: 0x1046b254c v8::internal::ScopeIterator::ScopeObject(v8::internal::ScopeIterator::Mode) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
6: 0x104aa2fb0 v8_inspector::V8DebuggerAgentImpl::currentCallFrames(std::__1::unique_ptr<std::__1::vector<std::__1::unique_ptr<v8_inspector::protocol::Debugger::CallFrame, std::__1::default_delete<v8_inspector::protocol::Debugger::CallFrame>>, std::__1::allocator<std::__1::unique_ptr<v8_inspector::protocol::Debugger::CallFrame, std::__1::default_delete<v8_inspector::protocol::Debugger::CallFrame>>>>, std::__1::default_delete<std::__1::vector<std::__1::unique_ptr<v8_inspector::protocol::Debugger::CallFrame, std::__1::default_delete<v8_inspector::protocol::Debugger::CallFrame>>, std::__1::allocator<std::__1::unique_ptr<v8_inspector::protocol::Debugger::CallFrame, std::__1::default_delete<v8_inspector::protocol::Debugger::CallFrame>>>>>>) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
7: 0x104aa280c v8_inspector::V8DebuggerAgentImpl::didPause(int, v8::Localv8::Value, std::__1::vector<int, std::__1::allocator> const&, v8::debug::ExceptionType, bool, v8::base::EnumSet<v8::debug::BreakReason, int>) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
8: 0x104ab56b4 v8_inspector::V8InspectorImpl::forEachSession(int, std::__1::function<void (v8_inspector::V8InspectorSessionImpl)> const&) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
9: 0x104aaaa40 v8_inspector::V8Debugger::handleProgramBreak(v8::Localv8::Context, v8::Localv8::Value, std::__1::vector<int, std::__1::allocator> const&, v8::base::EnumSet<v8::debug::BreakReason, int>, v8::debug::ExceptionType, bool) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
10: 0x1046ba754 v8::internal::Debug::OnDebugBreak(v8::internal::Handlev8::internal::FixedArray, v8::internal::StepAction, v8::base::EnumSet<v8::debug::BreakReason, int>) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
11: 0x1046ba074 v8::internal::Debug::Break(v8::internal::JavaScriptFrame*, v8::internal::Handlev8::internal::JSFunction) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
12: 0x104a214c4 v8::internal::Runtime_DebugBreakOnBytecode(int, unsigned long*, v8::internal::Isolate*) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
13: 0x10420fc74 Builtins_CEntry_Return2_ArgvOnStack_NoBuiltinExit [/opt/homebrew/Cellar/node/23.6.1/bin/node]
14: 0x1042e0368 Builtins_DebugBreak3Handler [/opt/homebrew/Cellar/node/23.6.1/bin/node]
15: 0x104178838 Builtins_InterpreterEntryTrampoline [/opt/homebrew/Cellar/node/23.6.1/bin/node]
16: 0x1041b5e20 Builtins_AsyncFunctionAwaitResolveClosure [/opt/homebrew/Cellar/node/23.6.1/bin/node]
17: 0x104283298 Builtins_PromiseFulfillReactionJob [/opt/homebrew/Cellar/node/23.6.1/bin/node]
18: 0x1041a5214 Builtins_RunMicrotasks [/opt/homebrew/Cellar/node/23.6.1/bin/node]
19: 0x1041763f0 Builtins_JSRunMicrotasksEntry [/opt/homebrew/Cellar/node/23.6.1/bin/node]
20: 0x1046f2718 v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
21: 0x1046f2e84 v8::internal::(anonymous namespace)::InvokeWithTryCatch(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
22: 0x10471d438 v8::internal::MicrotaskQueue::PerformCheckpointInternal(v8::Isolate*) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
23: 0x10417a978 Builtins_CallApiCallbackGeneric [/opt/homebrew/Cellar/node/23.6.1/bin/node]
24: 0x12818bbdc
25: 0x10417650c Builtins_JSEntryTrampoline [/opt/homebrew/Cellar/node/23.6.1/bin/node]
26: 0x1041761b0 Builtins_JSEntry [/opt/homebrew/Cellar/node/23.6.1/bin/node]
27: 0x1046f2740 v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
28: 0x1046f20a8 v8::internal::Execution::Call(v8::internal::Isolate*, v8::internal::Handlev8::internal::Object, v8::internal::Handlev8::internal::Object, int, v8::internal::Handlev8::internal::Object) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
29: 0x1045d73bc v8::Function::Call(v8::Isolate, v8::Localv8::Context, v8::Localv8::Value, int, v8::Localv8::Value) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
30: 0x1043316d4 node::InternalCallbackScope::Close() [/opt/homebrew/Cellar/node/23.6.1/bin/node]
31: 0x104331b94 node::InternalMakeCallback(node::Environment, v8::Localv8::Object, v8::Localv8::Object, v8::Localv8::Function, int, v8::Localv8::Value, node::async_context, v8::Localv8::Value) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
32: 0x104349c9c node::AsyncWrap::MakeCallback(v8::Localv8::Function, int, v8::Localv8::Value) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
33: 0x10451c37c node::StreamBase::CallJSOnreadMethod(long, v8::Localv8::ArrayBuffer, unsigned long, node::StreamBase::StreamBaseJSChecks) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
34: 0x10451c600 node::EmitToJSStreamListener::OnStreamRead(long, uv_buf_t const&) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
35: 0x104522b40 node::LibuvStreamWrap::OnUvRead(long, uv_buf_t const*) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
36: 0x104522848 node::LibuvStreamWrap::ReadStart()::$_1::__invoke(uv_stream_s*, long, uv_buf_t const*) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
37: 0x107a9ae6c uv__stream_io [/opt/homebrew/Cellar/libuv/1.50.0/lib/libuv.1.dylib]
38: 0x107aa20e0 uv__io_poll [/opt/homebrew/Cellar/libuv/1.50.0/lib/libuv.1.dylib]
39: 0x107a91f08 uv_run [/opt/homebrew/Cellar/libuv/1.50.0/lib/libuv.1.dylib]
40: 0x104332488 node::SpinEventLoopInternal(node::Environment*) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
41: 0x10445fef0 node::NodeMainInstance::Run(node::ExitCode*, node::Environment*) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
42: 0x10445fc44 node::NodeMainInstance::Run() [/opt/homebrew/Cellar/node/23.6.1/bin/node]
43: 0x1043d889c node::Start(int, char**) [/opt/homebrew/Cellar/node/23.6.1/bin/node]
44: 0x183ba0274 start [/usr/lib/dyld]
Activity
bnoordhuis commentedon Mar 25, 2025
Needs actual steps to reproduce (current one is too vague/imprecise) and please try with official node binaries, not homebrew's.
joyeecheung commentedon Apr 24, 2025
I ran into this when I was working on the HTTP proxy support in builtins, though unfortunately I forgot to record the breakpoints in time before I switched to work on something else. I am fairly certain that it appeared when I was stepping into a breakpoint in either _http_client.js or _http_agent.js when I was running a test added in https://github.com/joyeecheung/node/tree/http-agent-proxy-3 , likely somewhere around
node/lib/_http_client.js
Line 771 in 7a40aa7
heath-freenome commentedon May 30, 2025
I'm seeing this in my CI pipelines causing intermittent failures:
twilson90 commentedon Jul 5, 2025
Just ran into this too, using v24.3.0 on WIndows 11
joyeecheung commentedon Jul 7, 2025
FWIW I saw a slightly different crash again when debugging #58980. It might not be the same crash but I do have reproduction in https://github.com/joyeecheung/node/tree/http-agent-proxy-pr-crash
See repro and stacktrace
islandryu commentedon Aug 18, 2025
This error might be fixed by the following change.
https://chromium-review.googlesource.com/c/v8/v8/+/6507402
haiodo commentedon Sep 3, 2025
Same issue for 24.6.0
ecochard commentedon Sep 22, 2025
same for 24.8.0
bcazur commentedon Nov 23, 2025
I'm getting the same issue on node 24.2.0 on Mac. It reproduces consistently when stepping over a loop with async calls:
for await (const es of dataSeq) {...}
akc42 commentedon Nov 27, 2025
I have this trying to iterate over a Map in Node v24.11.0.
Im inside docker with a command started with
node --inspect-brk=0.0.0.0 server/migrate.jsand port 9229 mapped to the outside world. Dev tools is running on the outsideThis is all inside of an async function
I tried converting my map to an Array first
But that crashed too at the for loop. The conversion worked.
Finally i did
That worked
markb-trustifi commentedon Dec 4, 2025
The simple loop is also working:
LRagji commentedon Jan 1, 2026
Same issue when trying to debug and step into sync code of stream.write... Does anyone know what is broken and workaround? This is Mac Book pro and repeated in any LTS node version using nvm here.
github-actions commentedon Jul 20, 2026
This issue has been marked as stale due to 90 days of inactivity.
It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.
Tobbe commentedon Jul 25, 2026
Difficult to know if these are all the same or not, but adding my trace here as another datapoint
chore(ud-tests): Fail fast and retry when a V8 debugger bug kills the…
chore(ud-tests): Fail fast and retry when a V8 debugger bug kills the…
LukaszKokot commentedon Sep 4, 2026
We hit this check in an Electron app and tracked it down. And here's a reproducer that doesn't depend on any application code, since the steps in this thread have been hard to pin down.
[needscontext-repro.txt]: run
node needscontext-repro.mjs. It crashes on roughly 4 attempts in 10 on v24.15.0 (V8 13.6.233.17), macOS arm64.It spawns
node --inspect-brk victim.cjsand sendsRuntime.evaluateevery 2 ms while the script runs.The victim script just calls two closure-capturing functions in a loop.
Why it crashes
--inspect-brkmakes Node arm break-on-first-statement, so the entry module runs throughinspector.callAndPauseOnStart. Inspector messages arrive as V8 interrupts, and V8 services interrupts at the stack-guard call thatInterpreterEntryTrampolineemits at the start of a function, before the function's first bytecode runs.At that moment the frame exists but
CreateFunctionContexthasn't run, so the frame's context slot still holds the closure's own context. The queued evaluate then runs a script whose first bytecode trips the armed break. Building theDebugger.pausedpayload walks the scope chain of the frame underneath, wherefunction_->context() == *context_, and the check fires.Notice
pauses=0on every crashing attempt. The process dies while building the firstDebugger.pausednotification, which is why there's nothing to see on the client side.What this rules out
The varied reports in this thread make sense once you see the mechanism.
Stepping alone doesn't do it: V8 deliberately places a step's break after the context push, and every stepping variant I tried stayed clean. Pause volume doesn't do it either: one run hit ~118,000 pauses without crashing.
What seems to matter is only whether an inspector interrupt lands in the few instructions between the frame being built and its context being created. Sustained evaluate traffic reproduced it 9 times in 10.
Upstream status
V8 CL 7822241 proposed relaxing this check at function entry. Its author abandoned it, noting he couldn't reproduce locally.
(Description written with AI 🤖 and gently altered)
needscontext-repro.txt