denoland/deno · error · NodeError
ERR_HTTP_HEADERS_SENT
ERR_HTTP_HEADERS_SENT
Error message
Cannot write headers after they are sent to the client
What it means
ServerResponse.prototype.writeInformation (the path behind 1xx informational responses such as 102 Processing and 103 Early Hints) throws ERR_HTTP_HEADERS_SENT when this._header is already truthy: the final response's headers were already stored by an earlier writeHead or an implicit header flush. Informational responses are only legal before the final response begins, so the polyfill refuses to send them afterwards, matching Node.
Source
Thrown at ext/node/polyfills/_http_server.js:424
this.socket = null;
};
ServerResponse.prototype.writeContinue = function writeContinue(cb) {
this._writeRaw("HTTP/1.1 100 Continue\r\n\r\n", "ascii", cb);
this._sent100 = true;
};
ServerResponse.prototype.writeProcessing = function writeProcessing(cb) {
this._writeRaw("HTTP/1.1 102 Processing\r\n\r\n", "ascii", cb);
};
ServerResponse.prototype.writeInformation = function writeInformation(
statusCode,
headers,
cb,
) {
if (this._header) {
throw new ERR_HTTP_HEADERS_SENT("write");
}
if (typeof headers === "function") {
cb = headers;
headers = undefined;
}
validateInteger(statusCode, "statusCode", 100, 199);
let head = `HTTP/1.1 ${statusCode} ${
STATUS_CODES[statusCode] || "unknown"
}\r\n`;
if (headers !== null && headers !== undefined) {
const keys = ObjectKeys(headers);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
validateHeaderName(key);View on GitHub (pinned to 89f33cbef2)
Solutions
- Emit informational (1xx) responses before any writeHead/write/end on the final response
- Guard every call with if (!res.headersSent && !res._header)
- Fix middleware ordering so hints run at the top of the pipeline
- Once headers are sent, drop the hint - late 1xx carries no value to the client anyway
Example fix
// before
res.writeHead(200, { 'content-type': 'text/html' });
res.writeInformation(103, { link: '</style.css>' }); // throws
// after
if (!res.headersSent && !res._header) {
res.writeInformation(103, { link: '</style.css>' });
}
res.writeHead(200, { 'content-type': 'text/html' }); Defensive patterns
Strategy: validation
Validate before calling
function canSendInformational(res) {
return !res.headersSent && !res._header;
}
if (canSendInformational(res)) {
res.writeInformation(103, { 'link': '</style.css>' });
} Try / catch
try {
res.writeInformation(102);
} catch (e) {
if (e.code === 'ERR_HTTP_HEADERS_SENT') {
// final headers already flushed: skip the informational response
} else throw e;
} Prevention
- Emit 1xx responses at the top of the request pipeline, before any handler output
- Treat res.headersSent as a hard gate for every informational write
- Log skipped hints in tests so middleware ordering regressions surface early
When it happens
Trigger: Calling res.writeInformation(status, headers) or res.writeProcessing() after res.writeHead(), res.end(), or a res.write() that flushed the implicit header; early-hints middleware that runs after the route handler already started the response.
Common situations: Early-hints middleware ordered after the handler; streaming handlers that emit 102 Processing after the body started; retry/progress wrappers that report status too late in the request lifecycle.
Related errors
- ERR_HTTP_HEADERS_SENT
- ERR_HTTP_SOCKET_ASSIGNED
- ERR_INVALID_CHAR
- Unsupported 'alpnProtocols' option provided. 'h2' and 'http/
- ERR_INVALID_ARG_TYPE
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/3274ed30cbe8a7a0.
Report an issue: GitHub.