Bun.connect: native write() returns -1 (not raw -errno) on a peer RST and close carries ECONNRESET - #36422
Open
robobun wants to merge 12 commits into
Open
Bun.connect: native write() returns -1 (not raw -errno) on a peer RST and close carries ECONNRESET#36422robobun wants to merge 12 commits into
robobun wants to merge 12 commits into
Claude / Claude Code Review
completed
Jul 30, 2026 in 33m 10s
Code review found 3 important issues
Found 4 candidates, confirmed 3. See review comments for details.
Details
| Severity | Count |
|---|---|
| 🔴 Important | 3 |
| 🟡 Nit | 0 |
| 🟣 Pre-existing | 0 |
| Severity | File:Line | Issue |
|---|---|---|
| 🔴 Important | src/runtime/socket/socket_body.rs:1593-1598 |
on_end suppression never closes an allowHalfOpen socket — close(ECONNRESET) never fires |
| 🔴 Important | test/js/bun/net/socket.test.ts:3420-3423 |
RST test asserts Linux-only errno shape; will fail on macOS CI |
| 🔴 Important | src/runtime/socket/socket_body.rs:279-283 |
fatal_write_errno not reset on socket reconnect path |
Annotations
Check failure on line 1598 in src/runtime/socket/socket_body.rs
claude / Claude Code Review
on_end suppression never closes an allowHalfOpen socket — close(ECONNRESET) never fires
For `Bun.connect({ allowHalfOpen: true })`, this early return relies on "let `on_close` report the error", but with `allow_half_open` set loop.c never auto-closes after `on_end` — it only re-arms WRITABLE — so `on_close` never fires and the promised `close(ECONNRESET)` never arrives. The socket instead spins on level-triggered EPOLLHUP (each poll: WRITABLE→`on_writable` no-op, then eof→`on_end` suppressed→re-arm WRITABLE), and pre-PR the user at least got an `end` hook to call `socket.end()` and
Check failure on line 3423 in test/js/bun/net/socket.test.ts
claude / Claude Code Review
RST test asserts Linux-only errno shape; will fail on macOS CI
The last two assertions (`code === "ECONNRESET"` and `syscall === "write"`) encode Linux errno behavior; on macOS, `send()` to a peer-RST'd socket returns `EPIPE` without consuming `so_error`, so the close error surfaces as either `{code: "EPIPE", syscall: "write"}` or `{code: "ECONNRESET", syscall: "read"}` — the conjunction cannot hold and the test will fail on macOS CI. Either gate these two lines on `isLinux`, or relax to `expect(["ECONNRESET","EPIPE"]).toContain(code)` / `expect(["read","wr
Check failure on line 283 in src/runtime/socket/socket_body.rs
claude / Claude Code Review
fatal_write_errno not reset on socket reconnect path
`fatal_write_errno` is never cleared when a `NewSocket` wrapper is reused for reconnect (`detach_for_reconnect`, `connect_finish`'s `maybe_previous` branch, and the Windows named-pipe `prev` branches all skip it). A node:net socket that saw a peer RST, then reconnects — the code comments cite the MongoDB driver as a real user of this path — will on the *new* connection suppress `end` on a clean FIN (line 1593) and fabricate a spurious `ECONNRESET` / `syscall: 'write'` in `on_close` (line 2068) f
Loading