Repository navigation
Conversation
|
Warning Review limit reached
Next review available in: 4 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
Comment |
|
Updated 9:49 PM PT - Jul 8th, 2026
❌ @robobun, your commit 21ef4ad has 5 failures in
🧪 To try this PR locally: bunx bun-pr 33791That installs a local version of the PR into your bun-33791 --bun |
There was a problem hiding this comment.
LGTM — small, well-tested Node compat fix.
Extended reasoning...
Overview
This PR fixes session.socket on both ServerHttp2Session and ClientHttp2Session to return undefined after the session is destroyed, matching Node.js's documented behavior. Previously, if the proxy had been cached before destroy, the getter kept returning it (whose traps then throw ERR_HTTP2_SOCKET_UNBOUND on instanceof/property access), and the uncached path returned null instead of undefined. The fix is a 2-line reorder in each getter: check this[bunHTTP2Socket] first and return undefined when it's gone. A new test in test/js/node/http2/node-http2.test.js covers both the post-destroy undefined return and that a proxy reference captured before destroy still throws ERR_HTTP2_SOCKET_UNBOUND (preserving existing behavior verified by test-http2-unbound-socket-proxy.js).
Security risks
None. This is a getter return-value change in the Node http2 compat layer with no auth, crypto, or input-parsing implications.
Level of scrutiny
Low. The change is mechanical (reorder a guard, swap null → undefined), applied identically to both session classes, and bunHTTP2Socket is set synchronously in both constructors (lines 3811, 4761, 4786) and nulled on destroy/close (lines 4075, 4512, 4516, 4892) — so the only time the new early-return fires is post-teardown, exactly the case being fixed. No CODEOWNER covers these files.
Other factors
The test is well-constructed: port: 0, error handlers wired to reject awaited promises, awaits the close event instead of sleeping, cleanup in finally, and asserts both the new behavior and the preserved throwing behavior of pre-captured proxy references. The PR description confirms it fails on system Bun and passes on the debug build, and that the full http2 suite still passes. No outstanding reviewer comments.
There was a problem hiding this comment.
LGTM — small, well-scoped Node compat fix with a solid test.
Extended reasoning...
Overview
This PR fixes session.socket on both ServerHttp2Session and ClientHttp2Session to return undefined after the session is destroyed, matching Node.js's documented behavior. Previously, once the proxy was cached in #socket_proxy, the getter would keep returning it even after destroy() nulled bunHTTP2Socket, causing instanceof checks and truthiness guards in cleanup handlers to throw ERR_HTTP2_SOCKET_UNBOUND. The fix is a two-line reorder in each getter: check this[bunHTTP2Socket] first and return undefined when it's gone. It also corrects the uncached fallback from null to undefined.
Security risks
None. This is a pure JS getter reorder in the Node compat layer with no auth, crypto, or untrusted-input parsing involved.
Level of scrutiny
Low. The change is mechanical and symmetric across both session classes, directly implements documented Node semantics, and preserves the existing behavior for proxy references captured before destroy (they still throw ERR_HTTP2_SOCKET_UNBOUND, verified by both the new test and the existing test-http2-unbound-socket-proxy.js). I confirmed bunHTTP2Socket is nulled on the destroy/close paths, so the guard is live.
Other factors
The new test is well-constructed: port: 0, error events wired to reject the awaited promises, try/finally cleanup, and it exercises both the fresh-getter and stale-captured-proxy paths. The PR description shows it fails under USE_SYSTEM_BUN=1 and passes on the debug build. The bug-hunting system found no issues, and there is no CODEOWNERS entry for this file.
The Http2Session socket getter cached the Proxy wrapper in #socket_proxy and returned it unconditionally, even after destroy() had cleared the underlying bunHTTP2Socket. With the backing socket gone, every trap on that proxy (including getPrototypeOf, which instanceof calls) throws ERR_HTTP2_SOCKET_UNBOUND. So the ordinary post-teardown guard if (session.socket && !session.socket.destroyed) ... threw from inside cleanup code, and typeof session.socket reported 'object' where Node returns 'undefined'. Check bunHTTP2Socket first in both session classes and return undefined once it has been cleared, matching Node's documented behavior. A proxy captured before destroy still throws ERR_HTTP2_SOCKET_UNBOUND on access, which is also what Node does (test-http2-unbound-socket-proxy.js).
2289bde to
21ef4ad
Compare
There was a problem hiding this comment.
LGTM — small, well-scoped Node compat fix with a test that covers both the new undefined return and the preserved ERR_HTTP2_SOCKET_UNBOUND behavior on captured proxies.
Extended reasoning...
Overview
This PR fixes session.socket on both ServerHttp2Session and ClientHttp2Session to return undefined after the session is destroyed, matching Node.js's documented behavior. Previously, if the proxy had been cached, the getter kept returning the stale Proxy whose traps throw ERR_HTTP2_SOCKET_UNBOUND (breaking instanceof and truthiness guards in cleanup code); if uncached, it returned null instead of undefined. The fix reorders the getter to check this[bunHTTP2Socket] first and return undefined when it's gone. A new test in test/js/node/http2/node-http2.test.js verifies the post-destroy getter is undefined, that instanceof net.Socket no longer throws, and that a proxy reference captured before destroy still throws ERR_HTTP2_SOCKET_UNBOUND (preserving the behavior tested by Node's test-http2-unbound-socket-proxy.js).
Security risks
None. This is a pure getter-ordering change in the Node compat layer that only affects what session.socket returns after teardown. No auth, crypto, permissions, or untrusted-input parsing is touched.
Level of scrutiny
Low. The diff is ~8 lines of logic across two symmetric getters plus a focused test. bunHTTP2Socket is assigned synchronously in both constructors (lines 3811, 4761/4786) and nulled on destroy/close (4075, 4512, 4516, 4892), so the reordered check cannot cause undefined to be returned before destroy. The null → undefined change for the uncached path is a strict improvement toward Node parity.
Other factors
- Both session classes are updated identically, covering the whole class of the bug.
- The test wires
errorevents to reject and awaitscloserather than sleeping, follows harness conventions (port: 0, try/finally cleanup), and asserts both the fix and the preserved unbound-proxy contract. - No CODEOWNERS entry matches
src/js/node/http2.ts. - Bug hunter found no issues; PR description confirms the test fails on system Bun and passes on the debug build, and the full http2 suite still passes.
|
Diff is green. The only red lane on build #70778 is |
|
Closing: this change is already on main. #34432 (a07354a) made both The repro from this PR prints Main has no test for this behavior. #42255 carries the test from this PR over and extends it to the server session. |
Repro
Node documents that
session.socketisundefinedonce the session is destroyed. Bun kept returning the cached Proxy wrapper, whose traps (includinggetPrototypeOf, whichinstanceofcalls) throwERR_HTTP2_SOCKET_UNBOUNDonce the underlying socket is detached. The standard post-teardown guardif (session.socket && !session.socket.destroyed)therefore either saw a live-looking object or threw from inside cleanup code.Cause
Both
ServerHttp2SessionandClientHttp2Sessionimplement the getter as:destroy()nullsbunHTTP2Socketbut never touches#socket_proxy, so once the proxy was cached the first branch won forever. (And the uncached path returnednull, notundefined.)Fix
Check
bunHTTP2Socketfirst and returnundefinedwhen it is gone, in both session classes. A proxy reference captured before destroy still throwsERR_HTTP2_SOCKET_UNBOUNDon access, matching Node (test/js/node/test/parallel/test-http2-unbound-socket-proxy.js, which still passes).Verification
New test in
test/js/node/http2/node-http2.test.js:Full
node-http2.test.js: 294 pass, 6 skip, 1 pre-existing timeout (maxSessionMemory10k-request stress test under debug+ASAN, same on main).