From 591f59d552ac0f0194a87de7f6dceb9e02fef611 Mon Sep 17 00:00:00 2001 From: James Date: Sun, 26 Apr 2026 20:18:04 +0100 Subject: [PATCH] fix(dev): swallow socket errors so peer disconnects don't crash dev server MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Node throws on unhandled 'error' events on sockets. When the browser drops a connection mid-response (HMR triggers a reload while an RSC stream is still flushing), the next res.write surfaces ECONNRESET on res.socket with no listener attached and takes down `bun dev`. Attach a no-op error listener on every connection — same guard Vite's HMR server and Next.js install for the same reason. Closes #905. Co-Authored-By: Claude Opus 4.7 (1M context) --- packages/vinext/src/index.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/vinext/src/index.ts b/packages/vinext/src/index.ts index ec26d03164..60098c6d79 100644 --- a/packages/vinext/src/index.ts +++ b/packages/vinext/src/index.ts @@ -1993,6 +1993,18 @@ export default function vinext(options: VinextOptions = {}): PluginOption[] { } } + // Node throws on unhandled 'error' events on sockets. When a browser + // drops the connection mid-response (common in dev: HMR triggers a + // reload while an RSC stream is still flushing), the next res.write + // surfaces ECONNRESET on res.socket with no listener attached and + // takes down the process. A no-op listener on every connection + // neutralises the throw without hiding write failures from callers. + // Matches the guard Vite's HMR server and Next.js install for the + // same reason. See cloudflare/vinext#905. + server.httpServer?.on("connection", (socket) => { + socket.on("error", () => {}); + }); + server.watcher.on("add", (filePath: string) => { if (hasPagesDir && filePath.startsWith(pagesDir) && pageExtensions.test(filePath)) { invalidateRouteCache(pagesDir);