ERR_HTTP2_HEADERS_SENT
Node.jsERRORNotableHTTP/2HIGH confidence

HTTP/2 headers already sent for this stream

Production Risk

Crashes the stream handler; unhandled, it can bring down the HTTP/2 server process.

What this means

Thrown when an attempt is made to send HTTP/2 headers on a stream that has already sent its headers. HTTP/2 streams send headers as a single HEADERS frame; sending a second HEADERS frame is forbidden by the protocol.

Why it happens
  1. 1Calling stream.respond() more than once on the same stream
  2. 2Middleware that sets headers after a downstream handler has already responded
  3. 3Race conditions in async handlers where two code paths both call respond()
How to reproduce

Triggered when a second call to respond() is made on an HTTP/2 stream that already sent headers.

trigger — this will error
trigger — this will error
const http2 = require('http2');
const server = http2.createServer();
server.on('stream', (stream) => {
  stream.respond({ ':status': 200 });
  stream.respond({ ':status': 404 }); // throws
  stream.end();
});

expected output

Error [ERR_HTTP2_HEADERS_SENT]: Response has already been initiated

Fix

Guard with stream.headersSent before responding

WHEN In middleware or handlers that may be called multiple times

Guard with stream.headersSent before responding
server.on('stream', (stream) => {
  if (!stream.headersSent) {
    stream.respond({ ':status': 200 });
  }
  stream.end('ok');
});

Why this works

The headersSent flag lets you verify the response has not yet been initiated before calling respond().

Code examples
Triggerjs
const http2 = require('http2');
const server = http2.createServer();
server.on('stream', (stream) => {
  stream.respond({ ':status': 200 });
  stream.respond({ ':status': 404 }); // throws
  stream.end();  // this triggers ERR_HTTP2_HEADERS_SENT
Handle in try/catchjs
try {
  // operation that may throw ERR_HTTP2_HEADERS_SENT
  riskyOperation()
} catch (err) {
  if (err.code === 'ERR_HTTP2_HEADERS_SENT') {
    console.error('ERR_HTTP2_HEADERS_SENT:', err.message)
  } else {
    throw err
  }
}
Defensive pattern to avoid itjs
// Validate inputs before calling the operation
function safe_err_http2_headers_sent(...args) {
  // validate args here
  return performOperation(...args)
}
What not to do

Call respond() from multiple code paths without coordination

Only one HEADERS frame is allowed per stream.

Same error in other languages
Sources
Official documentation ↗

Node.js Error Codes Documentation

Content generated with AI assistance and reviewed for accuracy. Found an error? hello@errcodes.dev

← All Node.js errors