{"record":{"id":"3274ed30cbe8a7a0","repo":"denoland/deno","slug":"err-http-headers-sent-3274ed","errorCode":"ERR_HTTP_HEADERS_SENT","errorMessage":"Cannot write headers after they are sent to the client","messagePattern":"Cannot write headers after they are sent to the client","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/_http_server.js","lineNumber":424,"sourceCode":"  this.socket = null;\n};\n\nServerResponse.prototype.writeContinue = function writeContinue(cb) {\n  this._writeRaw(\"HTTP/1.1 100 Continue\\r\\n\\r\\n\", \"ascii\", cb);\n  this._sent100 = true;\n};\n\nServerResponse.prototype.writeProcessing = function writeProcessing(cb) {\n  this._writeRaw(\"HTTP/1.1 102 Processing\\r\\n\\r\\n\", \"ascii\", cb);\n};\n\nServerResponse.prototype.writeInformation = function writeInformation(\n  statusCode,\n  headers,\n  cb,\n) {\n  if (this._header) {\n    throw new ERR_HTTP_HEADERS_SENT(\"write\");\n  }\n\n  if (typeof headers === \"function\") {\n    cb = headers;\n    headers = undefined;\n  }\n\n  validateInteger(statusCode, \"statusCode\", 100, 199);\n\n  let head = `HTTP/1.1 ${statusCode} ${\n    STATUS_CODES[statusCode] || \"unknown\"\n  }\\r\\n`;\n\n  if (headers !== null && headers !== undefined) {\n    const keys = ObjectKeys(headers);\n    for (let i = 0; i < keys.length; i++) {\n      const key = keys[i];\n      validateHeaderName(key);","sourceCodeStart":406,"sourceCodeEnd":442,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/_http_server.js#L406-L442","documentation":"ERR_HTTP_HEADERS_SENT from ServerResponse.writeInformation(): 1xx informational responses (such as 103 Early Hints) are only valid before the final response headers exist. Once this._header is set — by writeHead(), a first write() that flushes implicit headers, or end() — writeInformation throws 'Cannot write headers after they are sent to the client'.","triggerScenarios":"res.writeInformation(103, {...}) called after res.writeHead(200), after the first res.write() already forced an implicit header flush, or after res.end().","commonSituations":"Early-Hints middleware that runs after the handler already streamed a response; async frameworks where a body write wins the race against the hints hook; double-invoked handlers during retries or error re-entry.","solutions":["Emit informational responses as the very first thing in the request lifecycle (a before-handler hook)","Guard every call with if (!res.headersSent) before writeInformation","If headers are already sent, skip the hint — it can no longer help the client"],"exampleFix":"// before\nres.writeHead(200, headers);\nres.writeInformation(103, { link: '</app.js>; rel=preload' }); // throws\n\n// after\nif (!res.headersSent) res.writeInformation(103, { link: '</app.js>; rel=preload' });\nres.writeHead(200, headers);","handlingStrategy":"validation","validationCode":"if (!res.headersSent && !res.writableEnded) {\n  res.writeInformation(103, hints);\n}","typeGuard":"const canSendInformational = (res) => !res.headersSent && !res.writableEnded;","tryCatchPattern":"try {\n  res.writeInformation(103, hints);\n} catch (e) {\n  if (e.code === 'ERR_HTTP_HEADERS_SENT') return; // too late for hints\n  throw e;\n}","preventionTips":["Register early-hints emission before any body-writing middleware","Check res.headersSent anywhere response state is uncertain","Keep informational responses in one place at the front of the request pipeline"],"tags":["http","early-hints","informational-response","server","node-compat"],"backgroundTag":"headers-already-sent","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}