{"record":{"id":"08ca817326bb5da1","repo":"denoland/deno","slug":"err-http-headers-sent","errorCode":"ERR_HTTP_HEADERS_SENT","errorMessage":"Cannot render headers after they are sent to the client","messagePattern":"Cannot render headers after they are sent to the client","errorType":"exception","errorClass":"NodeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/_http_client.js","lineNumber":767,"sourceCode":"\n    if (this[kProxy] && protocol === \"http:\") {\n      // Mirror what _storeHeader will pick for Connection: when shouldKeepAlive\n      // is true, both Connection and Proxy-Connection are \"keep-alive\"; when\n      // false, both are \"close\". Matches Node's wire format on the proxy hop.\n      if (!this.getHeader(\"proxy-connection\")) {\n        this.setHeader(\n          \"Proxy-Connection\",\n          this.shouldKeepAlive ? \"keep-alive\" : \"close\",\n        );\n      }\n      if (this[kProxy].auth && !this.getHeader(\"proxy-authorization\")) {\n        this.setHeader(\"Proxy-Authorization\", this[kProxy].auth);\n      }\n    }\n\n    if (this.getHeader(\"expect\")) {\n      if (this._header) {\n        throw new ERR_HTTP_HEADERS_SENT(\"render\");\n      }\n\n      this._storeHeader(\n        this.method + \" \" + this.path + \" HTTP/1.1\\r\\n\",\n        this[kOutHeaders],\n      );\n    }\n  } else {\n    this._storeHeader(\n      this.method + \" \" + this.path + \" HTTP/1.1\\r\\n\",\n      options.headers,\n    );\n  }\n\n  this[kUniqueHeaders] = parseUniqueHeadersOption(options.uniqueHeaders);\n\n  // Save options for potential stale keepalive retry\n  this[kRetryOptions] = optsWithoutSignal;","sourceCodeStart":749,"sourceCodeEnd":785,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/ext/node/polyfills/_http_client.js#L749-L785","documentation":"Inside ClientRequest's header-rendering path for requests carrying an 'expect' header (Expect: 100-continue), the code refuses to render headers twice: if this._header is already set when it needs to call _storeHeader again, it throws ERR_HTTP_HEADERS_SENT with the 'render' context. _header is assigned once headers have been serialized toward the socket, so this indicates a second rendering attempt after the request head was already produced.","triggerScenarios":"Using expect: '100-continue' and then triggering another implicit/explicit header generation after the head was sent — e.g. calling write()/end() again after headers flushed, or invoking internal header rendering twice via flows that re-enter _implicitHeader.","commonSituations":"Retry logic around 100-continue that re-invokes the request lifecycle on the same object; middleware that writes after the request was already flushed; double-processing of a paused/resumed request with expect set.","solutions":["Guard follow-up writes with if (!req.headersSent) before writing or re-rendering","Do not reuse a ClientRequest object for retries — create a new request instead","Drop the expect header unless you specifically implement the 100-continue handshake"],"exampleFix":"// before\nreq.on('error', () => { req.setHeader('retry', '1'); req.end(body); }); // after headers sent\n\n// after\nreq.on('error', () => {\n  if (!req.headersSent) { req.setHeader('retry', '1'); req.end(body); }\n  else { const retry = http.request(req.getHeaders()); retry.end(body); }\n});","handlingStrategy":"validation","validationCode":"if (req.getHeader('expect') && req.headersSent) {\n  throw new Error('request head already rendered; create a new request');\n}\n// only write/end while headersSent is false","typeGuard":null,"tryCatchPattern":"req.on('error', (e) => { if (e.code === 'ERR_HTTP_HEADERS_SENT') { /* abort this request, reissue a fresh ClientRequest */ } else throw e; });","preventionTips":["Check headersSent before any late write with expect: 100-continue","One request object per attempt; never re-render after flush","Implement 100-continue with the 'checkContinue' event instead of manual re-entry"],"tags":["http","headers","client","lifecycle","node-compat"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}