{"record":{"id":"26d64d4d50172e33","repo":"denoland/deno","slug":"err-socket-closed","errorCode":"ERR_SOCKET_CLOSED","errorMessage":"Socket is closed","messagePattern":"Socket is closed","errorType":"exception","errorClass":"NodeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/internal/http/address_override.js","lineNumber":225,"sourceCode":"  _read(_size) {\n    if (this._readResume) {\n      const resume = this._readResume;\n      this._readResume = null;\n      resume();\n    }\n  }\n\n  // Deno.Conn.write() is a single syscall-like write: it may write fewer\n  // bytes than provided (e.g. when the transport send buffer is full --\n  // vsock buffers are 64 KiB). Loop until the whole chunk is flushed.\n  async #writeAll(bytes) {\n    let nwritten = await this.#conn.write(bytes);\n    while (nwritten < bytes.length) {\n      const n = await this.#conn.write(\n        TypedArrayPrototypeSubarray(bytes, nwritten, bytes.length),\n      );\n      if (n === 0) {\n        throw new ERR_SOCKET_CLOSED();\n      }\n      nwritten += n;\n    }\n  }\n\n  _write(chunk, encoding, callback) {\n    const bytes = typeof chunk === \"string\"\n      ? Buffer.from(chunk, encoding)\n      : chunk;\n    // Any outgoing byte resets the idle timer too, matching net.Socket.\n    this.#armTimer();\n    PromisePrototypeThen(this.#writeAll(bytes), () => callback(), callback);\n  }\n\n  _final(callback) {\n    try {\n      // Allow the other side to finish reading while we finish writing.\n      if (this.#conn.closeWrite) {","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/internal/http/address_override.js#L207-L243","documentation":"Thrown by the polyfilled OverrideSocket (the Duplex wrapping a Deno.Conn for tunnel/vsock connections) when flushing a chunk. #writeAll() loops on conn.write() because a single write may be partial (vsock send buffers are 64 KiB); a return of 0 bytes means the transport is closed, so the chunk can never be delivered and ERR_SOCKET_CLOSED is raised into the write callback.","triggerScenarios":"res.write()/res.end() on a tunnel/vsock connection after the peer disconnected; a slow producer whose writes continue after the remote side reset; large responses being flushed in a loop when the peer closes mid-buffer.","commonSituations":"Clients aborting long downloads; proxies/tunnels forwarding after upstream closed; vsock guests shutting down while the host keeps writing; keep-alive writes hitting a dead connection.","solutions":["Treat ERR_SOCKET_CLOSED as terminal for that socket: stop writing and destroy it","Hook 'close'/'error' on the socket (and server 'clientError') and short-circuit further writes for that connection","Check socket.destroyed / socket.writable before each hot-path write","If writes legitimately race disconnects, pass a write callback and swallow this specific error after cleanup"],"exampleFix":"// before\nsocket.on(\"data\", (chunk) => peer.write(chunk)); // ERR_SOCKET_CLOSED after peer leaves\n\n// after\nsocket.on(\"data\", (chunk) => {\n  if (peer.destroyed) return socket.destroy();\n  peer.write(chunk, (err) => { if (err) peer.destroy(); });\n});\npeer.on(\"close\", () => socket.destroy());","handlingStrategy":"validation","validationCode":"function isSocketWritable(sock) {\n  return !sock.destroyed && !sock.closed && sock.writable !== false;\n}\nif (isSocketWritable(sock)) sock.write(chunk);","typeGuard":null,"tryCatchPattern":"sock.write(chunk, (err) => {\n  if (err && err.code === \"ERR_SOCKET_CLOSED\") {\n    sock.destroy(); // peer gone: stop writing this connection\n  }\n});","preventionTips":["Destroy the paired socket as soon as one side emits 'close' or 'error'","Guard hot-path writes with socket.writable/destroyed checks","Register 'error' handlers on every socket so closes never escalate to crashes"],"tags":["network","socket","write","vsock","tunnel","http"],"backgroundTag":"broken-pipe","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-31T04:17:50.494Z"}