← Debugging Guides

阅读中文版本

HTTP Content-Length Mismatch — Truncated or Extra Response

Fix Content-Length mismatch errors by letting the stack set the header, avoiding manual writes, and streaming with chunked transfer instead.

intermediatedebugginghttpheadersstreaming

Symptoms

  • The client errors with "premature end of Content-Length delimited message body"
  • Downloads are truncated or hang near completion
  • Setting Content-Length manually in the handler causes errors

Possible causes

  • Content-Length is set manually to a value that differs from the actual body bytes
  • The handler writes more or fewer bytes than declared
  • A proxy re-compresses or strips bytes but keeps the original length

Diagnosis steps

Compare declared length with delivered bytes

curl -s -D - https://api.example.com/file -o out.bin && wc -c out.bin

Interpretation

A delivered size different from the Content-Length header proves a mismatch.

Look for manual length handling

grep -rn "Content-Length\|content-length" src/

Interpretation

Manual length setting is the usual cause; let the framework compute it instead.

Root cause

When Content-Length is present, the client reads exactly that many bytes. If the server or a proxy sends a different number, the client reports a premature end or waits for bytes that never arrive.

Fix

Let the HTTP layer compute Content-Length from the actual body, avoid setting it manually, and for unknown-length streams use chunked transfer encoding (omit Content-Length) so the client reads until the terminating chunk.

Risk note

Combining compression with a manually set Content-Length is invalid; middleware that compresses must set length after compression or use chunked.

Verify the fix

Download the resource again and confirm the byte count matches the header; verify the full file hash is correct.

Symptoms

This debugging guide addresses “HTTP Content-Length Mismatch — Truncated or Extra Response”. Start from the symptoms, follow the ordered diagnostics, and confirm each hypothesis before moving on; the fix and verification steps then close the loop.

Observed symptoms include:

  • The client errors with “premature end of Content-Length delimited message body”
  • Downloads are truncated or hang near completion
  • Setting Content-Length manually in the handler causes errors

Reproduce and Diagnose

Reproduce the failure in isolation before changing any code. Work through the checks below in order; each one narrows the search space.

Step 1: Compare declared length with delivered bytes

curl -s -D - https://api.example.com/file -o out.bin && wc -c out.bin

A delivered size different from the Content-Length header proves a mismatch.

Step 2: Look for manual length handling

grep -rn "Content-Length\|content-length" src/

Manual length setting is the usual cause; let the framework compute it instead.

Likely contributors, in order of frequency:

  • Content-Length is set manually to a value that differs from the actual body bytes
  • The handler writes more or fewer bytes than declared
  • A proxy re-compresses or strips bytes but keeps the original length

Root Cause

When Content-Length is present, the client reads exactly that many bytes. If the server or a proxy sends a different number, the client reports a premature end or waits for bytes that never arrive.

The Fix

Let the HTTP layer compute Content-Length from the actual body, avoid setting it manually, and for unknown-length streams use chunked transfer encoding (omit Content-Length) so the client reads until the terminating chunk.

Watch out: Combining compression with a manually set Content-Length is invalid; middleware that compresses must set length after compression or use chunked.

// Express: let the framework set Content-Length from the body
res.json(payload); // length computed automatically

// streaming unknown-length response: use chunked (no Content-Length)
res.setHeader('Transfer-Encoding', 'chunked');
res.setHeader('Content-Type', 'text/event-stream');
stream.pipe(res); // ends with a terminating chunk

Verify and Prevent

Download the resource again and confirm the byte count matches the header; verify the full file hash is correct.

Once verified, add a regression test that reproduces the original symptom so the failure cannot silently return.

This class of failure is usually environmental rather than pure logic, so capture the exact command, the environment variables, and the working directory in your bug report. Reproduce it in the smallest possible script, then widen the scope only once the minimal case is understood. A short written checklist for this failure mode saves hours the next time it appears.