Repository navigation
Conversation
bun-types declares `error(socket, error)` for the handlers of Bun.udpSocket. The runtime passed the error as the only argument. `UDPSocket::call_error_handler` now passes the socket first, as `data` and `drain` do and as the handlers of Bun.listen and Bun.connect do. The node:dgram adapter takes the error from the second argument, so the 'error' event of a dgram socket does not change. A handler written as `error(err)` now receives the socket as `err`.
|
Status Reproduced on Bun 1.4.3-canary.1+367d939d9 and on a release build of main (Linux x64): const server = await Bun.udpSocket({
hostname: "127.0.0.1",
socket: {
data() {
throw new Error("boom");
},
error(...args) {
console.log(args.map(arg => Object.prototype.toString.call(arg)));
server.close();
client.close();
},
},
});
const client = await Bun.udpSocket({ hostname: "127.0.0.1" });
client.send("x", server.port, "127.0.0.1");Both print Tests: |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: oven-sh/bun/.coderabbit.yaml Review profile: ASSERTIVE Plan: Essentials Run ID: 📒 Files selected for processing (4)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review. WalkthroughUDP error callbacks now receive the socket as the first argument and the error as the second. The change updates runtime callback invocation, documents error cases, and adds runtime and type tests. ChangesUDP error callback
Suggested reviewers: Priority: ➖ Normal Severity of issue fixed: Medium Merge Risk: ⚪ Minimal · up to UDP error handlers now receive the socket before the error, so existing one-argument handlers need updating. The new contract is documented, and no separate code defect warrants holding the change. 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Comment |
There was a problem hiding this comment.
Beyond the inline findings, I checked for missed sibling sites: UDPSocket::call_error_handler is the only place the UDP error argv is built, so all three producers (recv error, data throw, drain throw) get the new (socket, error) shape, and src/js/node/dgram.ts is the only in-tree consumer of the Bun.udpSocket error handler.
Extended reasoning...
The runtime change is a one-line argv edit in src/runtime/socket/udp_socket.rs plus the matching dgram.ts adapter update, with JSDoc, docs, type fixtures and tests; it touches no security-sensitive surface. The user-observable break for one-parameter handlers (already an inline finding) is a direction call a maintainer must make, so this is not approvable by the bot.
Findings marked 🟡 are optional suggestions and need no follow-up push.
The docs section and the JSDoc of `error` now state that earlier versions of Bun call the handler with the error as the only argument. The receive-route test holds its refused port with a socket that is connected to another peer, so no other process can bind the port while the test runs. The test fails with a message if the socket closes before it calls `error`. The type fixture no longer depends on how TypeScript infers the `socket` parameter of an inline handler on a connected socket.
Fixes #44274
Problem
Bun.udpSocketcalls theerrorhandler with the error only. bun-types declareserror(socket, error).undefinedaserror. A read oferror.messagethrowsTypeError: undefined is not an object (evaluating 'error.message'), exit code 1.&[err]inUDPSocket::call_error_handler(src/runtime/socket/udp_socket.rs:871), from UDP support #7271.Fix
call_error_handler, the only caller, passes&[this_value, err]. Thenode:dgramadapter (src/js/node/dgram.ts:759) reads the second argument.data,drainand the TCPerrorhandler get the socket first. Public code has 52 handlers in that order and 2 in the other.test/js/bun/udp/udp_socket.test.ts, 1 inudp_socket_recv_flags.test.ts. They fail on 1.4.3-canary.1. Also thedgramandbun-typestests.reload()and overload declarations here (Bun.udpSocket: reload() reads the handlers fromsocket, bun-types declares reload(handlers) #44271, bun-types: handlers written inline on a connected Bun.udpSocket get the unconnected socket type #44272).Background
node:dgramruns onBun.udpSocket. Its adapter turns this callback into the'error'event.error(error)in the types: it repairs no existing handler. ConsideredFunction.length: bun-types cannot declare it.Downsides
error(err)now gets the socket. The v1.3.12 release notes show that form. A handler that rethrows all butECONNREFUSEDnow throws each time.errorhandler gets (error), bun-types declares (socket, error) #44274). docs, bun-types: fix seven statements that do not match runtime behavior #41728 takes the other direction forBun.servewebsocket.error. Proposal: the next minor.Notes
The break. bun-types does not change, so a handler with one parameter gets no compile error.
Change the handler to
error(socket, err). A handler that must run before and after this change can useerror(a, b) { const err = b ?? a; }. The release post https://bun.com/blog/bun-v1.3.12 shows the one-parameter form. It lives outside this repository and needs the same edit.One send from a connected socket to a closed port on Linux (release builds, 3 runs each):
errorhandlerECONNREFUSED, exit code 1error(socket, error), readserror.messageTypeError, exit code 1error(socket, error), logserrorundefinederror(err), readserr.code"ECONNREFUSED"undefinederror(err), returns onECONNREFUSED, throws the restThe
node:dgram'error'event and a socket with no handler do not change.Demand. No issue reported this before #44274. The evidence is public code: a GitHub code search for
Bun.udpSocket error(2026-09-27, 206 files) has 63errorhandlers in 44 repositories.errorwith no guard and throw when they run. 34 log or forwarderrorand getundefined. 5 read both positions, so their authors found the mismatch. 3 do not useerror.ECONNREFUSEDand throws the rest. One logs its argument....args.error(error)in CPU 100% on UDP error !!!! #29436 and UDP Socket not working when listening to IPv6 address #15612,error(socket, error)in UDP Sockets not working outside of local computer #11365.Direction. #44274 has the two options and the questions for a maintainer. The same mismatch exists for
websocket.errorofBun.serve: the docs show(ws, error), the runtime passes(error), and bun-types has no member. #41728 (open, approved) declareserror?(error: unknown)there. #36033 changed the runtime there and was closed as stale. #11634 is the report. bun-types declared the UDP handler from the start, which is the difference.History.
error(socket, error)anddgram.tsregisterederror: (_socket, error) => .... The native call passed one argument.dgram.tstoerror: error =>.Docs and types.
this.errorwith the error only. They name no version, because the release is not decided (Bun.udpSocket: theerrorhandler gets (error), bun-types declares (socket, error) #44274).bun initcompiler options) and run on Linux. They printinvalid packet,falseandECONNREFUSED.udp_socket_recv_flags.test.tsruns the second snippet's case there in CI.dgram.test.ts("connected socket emits the ICMP error") already covers the same native path.fixture/udp.tscompiles the docs usage. It does not cover the type ofsocketin inline handlers of a connected socket (bun-types: handlers written inline on a connected Bun.udpSocket get the unconnected socket type #44272).Measurements (linux-x64, release builds of one checkout, with and without the two source lines).
thisis the socket before and after.error() {}+16,error(socket, error) {}+16 (634 to 650). gdbstepicount from the entry ofcall_error_handlerto its return, at deliveries 500, 501 and 502, 2 runs per build, no spread. valgrind and perf are not installed in the container.call_error_handler+4 B (509 B to 513 B), one moremovq..text+0 B..bun_builtins+9 B (thedgram.tssource). File +0 B (80,827,976 B).on_data/on_drain/on_recv_error/UDPSocketConfig::from_js: 0 differing instructions, sizes unchanged. Host functions +0, codegen rows +0,UDPSocketfields +0.dgram.test.ts62 pass, 0 fail, andtest-dgram-recv-error.jsexits 0, with the test files unedited. With a stale one-parameter adapter, 3 tests ofdgram.test.tsfail. One of them runs on every platform.bun-types.test.ts22 pass, 0 fail. With both declarations flipped to one parameter, tsc 6.0.2 reports 13 diagnostics infixture/udp.ts.bun.d.ts+1,406 B. Unpacked +2,734 B, which includes +1,328 B ofudp.mdx. Packed +548 B.Suites run on the debug build.
test/js/bun/udp/udp_socket.test.ts: 238 pass, 0 fail.test/js/bun/udp/udp_socket_recv_flags.test.ts: 3 pass, 0 fail. 2 of the 3 fail on 1.4.3-canary.1: the new row, and the Linux ICMP test, whose handler at line 58 had one parameter and was aTS2769on main.test/js/bun/udp/dgram.test.ts: 62 pass, 0 fail.test/js/node/test/parallel/test-dgram-recv-error.js: exit 0.test/js/bun/module-graph/module-graph-io.test.ts: 26 pass, 1 fail. The failure is "through a CONNECT proxy", a 5 s timeout under the debug build. It passes in 7.7 s with--timeout 120000. The test does not use UDP.Test notes.
datathrows,drainthrows} x {handlers fromudpSocket(), handlers fromreload()}.drainrows send nothing. A new socket reports writable once, sodrainruns with no send.reload()rows callreload({ socket }), the shape that the runtime reads. bun-types rejects it (Bun.udpSocket: reload() reads the handlers fromsocket, bun-types declares reload(handlers) #44271).udp_socket_recv_flags.test.tscovers the receive route for a connected socket on Linux and macOS. A socket that is connected to another peer holds the target port. The kernel refuses the datagrams, and no other process can bind the port during the test.Not in this PR.
reload(): bun-types declaresreload(handlers), the runtime readsoptions.socketand resetsbinaryType(Bun.udpSocket: reload() reads the handlers fromsocket, bun-types declares reload(handlers) #44271).websocket.errorofBun.serve(WebSockets documentation includes nonexistent "error" handler #11634, docs, bun-types: fix seven statements that do not match runtime behavior #41728).thisis the socket in every UDP handler at runtime. bun-types does not declare it.error: Erroris not exact. A thrown value is passed as thrown, and a system error hascode. The docs snippet usesBun.SystemError.dataordrainreturns is not awaited. A rejection does not reacherror. The docs and JSDoc now say so.bsd_recvmmsgdrops the ICMP resets, and any other failed receive closes the socket with no callback (packages/bun-usockets/src/loop.c).send()on a connected socket can throw the pendingECONNREFUSEDon Linux.test/.Open PRs with the one-parameter form.
error(err)test handler on its branch.error: guardCallback(error => ...).dgram.test.tstests above fail if the adapter is stale.no test proof · iteration 0 · platform-specific test(s) that do not run on this machine, deferring to CI, which covers all platforms: test/js/bun/udp/udp_socket_recv_flags.test.ts, test/js/bun/udp/udp_socket.test.ts