Skip to content

inspector: load network tracking modules eagerly - #64379

Open
harjothkhara wants to merge 2 commits into
nodejs:mainfrom
harjothkhara:fix/inspector-network-tracking-eager-load
Open

harjothkhara wants to merge 2 commits into
nodejs:mainfrom
harjothkhara:fix/inspector-network-tracking-eager-load

Conversation

@harjothkhara

@harjothkhara harjothkhara commented Jul 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

--experimental-network-inspection can abort the whole Node.js process when a debugger attaches. Reported in #64308.

Network.enable is delivered to the main thread via a V8 interrupt that can run in the middle of arbitrary JavaScript execution, including while another module is still being loaded by require(). Enabling network tracking called back into JS from that interrupt (Agent::ToggleNetworkTracking) to lazily require() the tracking modules, which pull in inspector, worker_threads and stream. When the interrupt lands mid-require(), require() returns a half-initialized module and throws (for example Class extends value undefined from internal/worker/io), and the agent calls UNREACHABLE(), aborting the process.

Fix

As suggested by @legendecas: when --experimental-network-inspection is set, load the tracking modules and subscribe their diagnostics channels at startup. Network.enable/Network.disable now only flip NetworkInspector::enabled_, which already gates event emission in NetworkAgent::emitNotification, so nothing calls into JS from the interrupt.

The now unused setupNetworkTracking binding, the inspector_{enable,disable}_network_tracking env properties and Agent::{Enable,Disable,Toggle}NetworkTracking are removed.

Because the channels are now subscribed before any debugger attaches, the handlers check internalBinding('inspector').isNetworkDomainEnabled() (true if any session has Network enabled) before assigning a request id. Requests started before Network.enable are not tracked, so the frontend never gets loadingFinished/loadingFailed for a request it never saw, and the per-request cost while no session is listening is a single native call.

Verification

Repro from the issue: node --inspect-wait --experimental-network-inspection -e "require('net')", then attach and send Network.enable.

Driving the real inspector path (attach over WebSocket, Runtime.runIfWaitingForDebugger, then Network.enable with 0-15 ms jitter across the require() window):

  • stock v24.16.0: 4 crashes in 50 runs
  • this branch: 0 crashes in 100 runs

Tests:

  • test-inspector-network-tracking-eager-load.js: tracking modules are loaded and their channels subscribed at startup.
  • test-inspector-network-pre-enable-request.js: http, failing http and fetch requests started before Network.enable and finished after it emit no events; a request started afterwards gets the full sequence.

Fixes: #64308

AI disclosure: parts of this change were drafted with the help of an AI coding assistant. I've reviewed, tested and take responsibility for the result.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/inspector

@nodejs-github-bot nodejs-github-bot added the needs-ci PRs that need a full CI run. label Jul 9, 2026
@harjothkhara

Copy link
Copy Markdown
Contributor Author

@legendecas mind taking a look or kicking off CI when you have a moment? Open ~4 weeks with no CI run yet — small, tested fix for #64308.

@legendecas legendecas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Related to #65028, I think this does not fully fix the issue of calling into JS during an interrupt. An alternative could be loading the tracking module when --experimental-network-inspection is set at startup, and enable it immediately.

@harjothkhara

Copy link
Copy Markdown
Contributor Author

Thanks @legendecas. You're right: #65028 changes the async hook toggle, but not ToggleNetworkTracking, so #64308 can still call into JS from the interrupt. This is only a partial fix.

Your alternative works for me: with --experimental-network-inspection, load and enable tracking at startup so Network.enable doesn't toggle anything.

I can rework the PR this way, or make ToggleNetworkTracking interrupt-aware on top of #65028. Which do you prefer?

@harjothkhara
harjothkhara force-pushed the fix/inspector-network-tracking-eager-load branch from cef8981 to 39e1c36 Compare October 14, 2026 23:03
`Network.enable` is dispatched to the main thread through a V8 interrupt
that can run in the middle of arbitrary JavaScript execution, including
while another module is still being loaded by require(). Enabling
network tracking called back into JS from that interrupt to lazily
require() the tracking modules, which pull in `inspector`,
`worker_threads` and `stream`. When the interrupt landed mid-require(),
require() returned a half-initialized module and threw (for example
"Class extends value undefined" from internal/worker/io). The inspector
agent treats any exception thrown while toggling network tracking as
unrecoverable and aborts the whole process.

When --experimental-network-inspection is set, load the tracking modules
and subscribe their diagnostics channels at startup instead.
Network.enable/Network.disable now only flip the flag that gates event
emission in NetworkInspector, so they never call into JS from an
interrupt. The now unused setupNetworkTracking binding and the agent's
enable/disable toggling are removed.

Fixes: nodejs#64308
Signed-off-by: harjoth <harjoth.khara@gmail.com>
Assisted-by: Claude
With the network tracking channels subscribed at startup, a request
created before any session enabled the Network domain was still given
an inspector request id, while its Network.requestWillBeSent was
dropped natively. If that request finished or failed after
Network.enable, the frontend received Network.loadingFinished or
Network.loadingFailed for a request it had never seen.

Expose whether any session has the Network domain enabled and only
assign request ids, and so track a request, while it is.

Refs: nodejs#64308
Signed-off-by: harjoth <harjoth.khara@gmail.com>
Assisted-by: Claude, Codex
@harjothkhara
harjothkhara force-pushed the fix/inspector-network-tracking-eager-load branch from 39e1c36 to a39b402 Compare October 15, 2026 00:32
@harjothkhara

Copy link
Copy Markdown
Contributor Author

@legendecas reworked as you suggested: with --experimental-network-inspection, network tracking now loads at startup, so Network.enable no longer calls into JS from the interrupt. This fully fixes #64308. Requests started before Network.enable are skipped, so the frontend never gets events for requests it didn't see. Rebased on main, tests added. PTAL, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unreachable code reached, Cannot toggle network tracking

3 participants