Content-Length mismatch errors (tested)

A wrong Content-Length header causes truncated responses, hanging requests and errors such as curl (18) or net::ERR_CONTENT_LENGTH_MISMATCH. We sent eight broken responses from a raw Node server to four clients and wrote down exactly what each one did.

1. The results

The body was always the 11 bytes hello world. "OK" means the client returned without error; the quoted text is the body it gave back.

Response sentcurl 8.14.1Node 24 fetch (undici)Python requests 2.32.3Chromium 153 fetch() / navigation
Content-Length: 5 (smaller than body)OK, "hello" (exit 0)OK, "hello"OK, "hello"OK, "hello" / page shows "hello"
Content-Length: 20, server closes after 11 bytescurl: (18) end of response with 9 bytes missingTypeError: terminated, cause UND_ERR_SOCKET "other side closed"ChunkedEncodingError: "Connection broken: IncompleteRead(11 bytes read, 9 more expected)"TypeError: Failed to fetch / navigation status 200, then net::ERR_CONTENT_LENGTH_MISMATCH
Content-Length: 20, connection left openHangs; with -m 3: curl: (28) Operation timed out after 3002 milliseconds with 11 out of 20 bytes receivedHangs until our 3 s AbortSignal timeout (TimeoutError)Hangs until timeout: ConnectionError "Read timed out."fetch() hangs until our abort / navigation did not finish within 4 s
Two identical lines: Content-Length: 11 twiceOK, full bodyTypeError: fetch failed, cause UND_ERR_RES_CONTENT_LENGTH_MISMATCH "Response body length does not match content-length header"OK, full bodyOK, full body (both)
Two different values: 11 and 5OK, but body cut to "hello" (verbose: "Excess found writing body")UND_ERR_RES_CONTENT_LENGTH_MISMATCH (same as above)InvalidHeader: "Content-Length contained multiple unmatching values (11, 5)"TypeError: Failed to fetch / net::ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH
Content-Length: 5 plus Transfer-Encoding: chunked (valid chunked body)OK, full body (chunked used)UND_ERR_RES_CONTENT_LENGTH_MISMATCHOK, full bodyOK, full body (both)
Content-Length: -1curl: (8) Invalid Content-Length: valueTypeError: fetch failed: "Response does not match the HTTP/1.1 protocol (Invalid character in Content-Length)"OK, full body (read until close)OK, full body (both)
Content-Length: abccurl: (8) Invalid Content-Length: valueSame "Invalid character in Content-Length" errorOK, full body (read until close)OK, full body (both)

The Node fetch result for two identical Content-Length lines surprised us: every other client accepted it, but undici in Node 24.21.0 rejected it with a length mismatch error. If a proxy or framework in front of your Node code duplicates the header, Node fetch clients can fail while browsers and curl work.

2. What this means in practice

When to expect Content-Length versus chunked in the first place is covered in Transfer-Encoding chunked vs Content-Length.

3. Node http server with a wrong Content-Length

http.createServer((req, res) => {
  res.setHeader('Content-Length', '20');   // body below is 11 bytes
  res.end('hello world');
});

In Node 24.21.0 with default options, res.end() did not throw and nothing was logged. Node sent the header as given. With Content-Length 20, curl got 11 bytes and then hung until its timeout (curl: (28) ... with 11 out of 20 bytes received), because Node kept the keep-alive connection open. With Content-Length 5, curl received "hello" and exit code 0.

Doc-based, not tested here: Node's http.createServer({ strictContentLength: true }) option makes Node throw ERR_HTTP_CONTENT_LENGTH_MISMATCH instead of sending a mismatched body. The safest fix is to not set Content-Length by hand at all; res.end(body) sets a correct one for you when headers have not been sent yet. If you do set it, use Buffer.byteLength(body), not body.length, because non-ASCII characters take more than one byte in UTF-8.

4. Common causes

5. How to check

curl -sv -o body.bin https://example.com/path
wc -c body.bin    # compare with the Content-Length line in the -v output

curl's verbose output shows each Content-Length line it received, and the error codes above (18 and 8) point straight at the problem. You can also see the headers of any URL with the free HTTP headers checker.

Frequently asked questions

What does curl: (18) mean?

In curl 8.14.1 we got 'curl: (18) end of response with 9 bytes missing' when the server promised Content-Length: 20, sent 11 bytes and closed the connection. The body is shorter than the header says.

What causes net::ERR_CONTENT_LENGTH_MISMATCH in Chrome?

In Chromium 153, a navigation to a response with Content-Length: 20 and only 11 bytes before the server closed the connection failed with net::ERR_CONTENT_LENGTH_MISMATCH. fetch() in the same case rejected with TypeError: Failed to fetch.

What happens if Content-Length is smaller than the body?

Every client we tested (curl, Node fetch, Python requests, Chromium) returned only the first N bytes with no error. The extra bytes were silently dropped.

Why does my request hang when Content-Length is too large?

If the server keeps the connection open, the client waits for the missing bytes. curl, Node fetch, Python requests and Chromium all waited until a timeout in our test.

Is it OK to send Content-Length twice?

Two identical values worked in curl, Python requests and Chromium 153, but Node 24 fetch rejected it with UND_ERR_RES_CONTENT_LENGTH_MISMATCH. Two different values were rejected by Python, Chromium and Node fetch, and curl cut the body to the second value. Send it once.

Written with AI assistance. Measured on 2026-10-01 against a raw Node.js 24.21.0 net server on 127.0.0.1 sending hand-written HTTP/1.1 responses with an 11-byte body (hello world). Clients: curl 8.14.1, Node 24.21.0 fetch (undici), Python requests 2.32.3, and Chromium 153.0.8010.12 (Playwright, full chromium channel) for both fetch() and page navigation. Also a Node http server with a wrong Content-Length set by hand. PlainHeaders is our extension; the other methods are free.