Hmbown/CodeWhale · warning · FormBodyError
invalid Content-Length
Error message
invalid Content-Length
What it means
FormBodyError with HTTP 400: a Content-Length header was present but did not match /^\d+$/ - it contained a sign, whitespace, hex, or garbage. The check runs before any body read so the size limit decision never trusts a malformed value.
Source
Thrown at web/lib/bounded-form.ts:22
message: string
) {
super(message);
this.name = "FormBodyError";
}
}
export async function readBoundedUrlEncodedForm(
request: Request,
maxBytes: number
): Promise<URLSearchParams> {
const mediaType = request.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
if (mediaType !== "application/x-www-form-urlencoded") {
throw new FormBodyError(415, "expected application/x-www-form-urlencoded");
}
const rawLength = request.headers.get("content-length");
if (rawLength !== null) {
if (!/^\d+$/.test(rawLength)) throw new FormBodyError(400, "invalid Content-Length");
if (Number(rawLength) > maxBytes) throw new FormBodyError(413, "payload too large");
}
if (!request.body) return new URLSearchParams();
const reader = request.body.getReader();
const chunks: Uint8Array[] = [];
let total = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
total += value.byteLength;
if (total > maxBytes) {
try {
await reader.cancel("payload too large");
} catch {
// A source cancellation error must not obscure the enforced size limit.
}View on GitHub (pinned to 8880682c63)
Solutions
- Remove the custom Content-Length and let the HTTP stack compute it
- Fix middleware/proxy logic that rewrites the header
- Replay the request without the header to confirm it was the cause
Example fix
// before
fetch(url, { method: 'POST', headers: { 'content-length': String(payload.length * 2) }, body: payload });
// after - omit content-length; the client computes it
fetch(url, { method: 'POST', headers: { 'content-type': 'application/x-www-form-urlencoded' }, body: payload }); Defensive patterns
Strategy: validation
Validate before calling
const len = headers.get('content-length');
if (len !== null && !/^\d+$/.test(len)) {
headers.delete('content-length'); // let the transport recompute it
} Try / catch
try {
const params = await readBoundedUrlEncodedForm(request, MAX_BYTES);
} catch (err) {
if (err instanceof FormBodyError && err.status === 400) {
return new Response('malformed request headers', { status: 400 });
}
throw err;
} Prevention
- Never hand-set Content-Length in fetch/axios calls
- Audit proxies and middleware that rewrite hop-by-hop headers
- Treat non-digit Content-Length as a client bug, not something to coerce
When it happens
Trigger: A client, proxy, or middleware injecting a malformed Content-Length such as ' 123', '-1', '0x40', or '1e3'; test tooling overriding the header by hand.
Common situations: Devtools/Postman manual overrides; a middleware recomputing the header from a float; hand-rolled HTTP clients that format numbers badly.
Related errors
- expected application/x-www-form-urlencoded
- payload too large
- ${detail || ("HTTP " + res.status)}
- ${response.status} ${response.statusText}
- unknown argument: ${arg}
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/d06e38a0440d0d84.
Report an issue: GitHub.