denoland/deno · error · NodeError

ERR_HTTP_CONTENT_LENGTH_MISMATCH

ERR_HTTP_CONTENT_LENGTH_MISMATCH

Error message

Response body's content-length of ${this[kBytesWritten]} byte(s) does not match the content-length of ${this._contentLength} byte(s) set in header

What it means

On end(), OutgoingMessage enforces strict content-length: when _checkStrictContentLength(msg) is true (msg.strictContentLength enabled AND a content-length is set AND the message has a body AND it is not chunked and content-length was not removed), it compares kBytesWritten (bytes actually written) with _contentLength (the declared header value). Any difference throws ERR_HTTP_CONTENT_LENGTH_MISMATCH instead of sending a lying header.

Source

Thrown at ext/node/polyfills/_http_outgoing.ts:614

        return this;
      } else if (!this._header) {
        if (this.socket) {
          this.socket.cork();
        }

        this._contentLength = 0;
        this._implicitHeader();
      }

      if (typeof callback === "function") {
        this.once("finish", callback);
      }

      if (
        _checkStrictContentLength(this) &&
        this[kBytesWritten] !== this._contentLength
      ) {
        throw new ERR_HTTP_CONTENT_LENGTH_MISMATCH(
          this[kBytesWritten],
          this._contentLength,
        );
      }

      const finish = FunctionPrototypeBind(onFinish, undefined, this);

      if (this._hasBody && this.chunkedEncoding) {
        this._send("0\r\n" + this._trailer + "\r\n", "latin1", finish);
      } else if (!this._headerSent || this.writableLength || chunk) {
        this._send("", "latin1", finish);
      } else {
        (globalThis as any).process.nextTick(finish);
      }

      if (this.socket) {
        // Fully uncork connection on end().
        this.socket._writableState.corked = 1;

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Compute the length from the exact bytes sent: Buffer.byteLength(body, encoding)
  2. Apply all transformations (compression, templating) before measuring and setting content-length
  3. For unknown-size streams, remove the content-length header and use chunked transfer-encoding instead

Example fix

// before
res.setHeader('content-length', body.length); // 'héllo'.length = 5, bytes = 6
res.end(body);

// after
res.setHeader('content-length', Buffer.byteLength(body));
res.end(body);
Defensive patterns

Strategy: validation

Validate before calling

const body = Buffer.from(payload, 'utf8');
res.setHeader('content-length', body.length);
res.end(body); // byte count always matches under strictContentLength

Try / catch

try { res.end(body); } catch (e) { if (e.code === 'ERR_HTTP_CONTENT_LENGTH_MISMATCH') { /* recompute length from actual bytes and reissue response */ } else throw e; }

Prevention

When it happens

Trigger: setHeader('content-length', Buffer.byteLength(bodyA)) then end(bodyB) where the bodies differ; string vs byte miscounts (content-length computed on .length of a multibyte string); streams where the declared length does not match actual chunk sizes under strictContentLength servers.

Common situations: Manually setting content-length for keep-alive reuse but the body is transformed (gzip, template substitution) after counting; using str.length instead of Buffer.byteLength(str, encoding) for UTF-8; mutating the body between the length computation and end().

Related errors


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/e2f04bfaae9ed5b7. Report an issue: GitHub.