< HTTP/1.1 411 Length Required411 Length Required: Why It Happens
411 Length Required: the server wants a Content-Length and got chunked or none. Fix it in curl, Node, Python and fetch, and on nginx and Google Frontend.
- Cacheable
- Only with explicit freshness
- Retry?
- Yes, with a Content-Length header
- Usually sent by
- Web server or proxy
On this page
TL;DR: 411 means the server (or a proxy in front of it) refuses a request body unless it comes with a
Content-Length. The usual triggers are chunked uploads and empty POSTs with noContent-Length: 0. Send an explicit length, or move to HTTP/2.
What it means
An HTTP/1.1 request body is delimited either by Content-Length or by Transfer-Encoding: chunked (RFC 9112 §6). Many servers handle both. Some refuse chunked requests, some require a length for specific methods, some want it to enforce size limits before reading. RFC 9110 §15.5.12 lets them answer 411.
PUT /uploads/video.mp4 HTTP/1.1
Host: storage.example.com
Transfer-Encoding: chunked
HTTP/1.1 411 Length Required
Content-Length: 0
Connection: close
The cases people actually hit
1. Empty POST with no length. curl -X POST https://api.example.com/jobs/42/cancel sends no body and no Content-Length. Some stacks do not infer zero and answer 411. Google Frontend’s HTML error is the best-known version:
411. That's an error.
POST requests require a Content-length header. That's all we know.
Fix it with -d '' or -H 'Content-Length: 0'.
2. Chunked upload to something that cannot take chunks. Any HTTP client that streams a body of unknown size on HTTP/1.1 switches to Transfer-Encoding: chunked. Examples: piping stdin to curl (cat file | curl -T - ...), passing a generator to Python requests, piping a stream into Node’s http.request without a length, or fetch with a ReadableStream body (which requires duplex: 'half'). Targets that answer 411: S3 (MissingContentLength, “You must provide the Content-Length HTTP header”), older nginx versions in front of an app, some CDNs and WAFs, and many reverse proxies in front of legacy endpoints.
3. A proxy that buffers or strips. A gateway converts HTTP/2 or HTTP/3 to HTTP/1.1, the client had no length, and the next hop refuses chunked.
4. WAF or API gateway policy. Some gateways require a declared length so they can reject oversized bodies before reading them.
Fix it
Give the length, which means knowing it before sending:
# curl: let it measure the file
curl -T video.mp4 https://storage.example.com/uploads/video.mp4
curl --data-binary @payload.json -H 'Content-Type: application/json' https://api.example.com/v1/events
# stdin forces chunked; avoid, or force the length yourself
cat payload.json | curl -X POST --data-binary @- https://api.example.com/v1/events # curl reads all of stdin first
import requests, os
# generator body -> chunked -> 411 on strict servers
# requests.put(url, data=chunks())
# file object: requests sets Content-Length from the file
with open("video.mp4", "rb") as f:
requests.put(url, data=f)
import { request } from 'node:http'
import { createReadStream, statSync } from 'node:fs'
const size = statSync('video.mp4').size
const req = request(
{ host: 'storage.example.com', method: 'PUT', path: '/uploads/video.mp4',
headers: { 'Content-Length': size } },
(res) => console.log(res.statusCode)
)
createReadStream('video.mp4').pipe(req)
If the body size really is unknown (a live stream, a computed archive), options are: buffer to disk or memory to learn the size, use S3 multipart upload (each part has a known size), or talk HTTP/2 to the endpoint.
If you operate the server
nginx has accepted chunked request bodies since 1.3.9, so a 411 from an up-to-date nginx is rare and normally comes from an app behind it. When nginx proxies to an upstream that cannot take chunked requests, proxy_request_buffering on; (the default) makes nginx read the whole body and forward it with a Content-Length. If you have set proxy_request_buffering off; for streaming, that is where chunked starts reaching the upstream.
location /uploads/ {
proxy_pass http://legacy_backend;
proxy_request_buffering on; # default; buffers and sets Content-Length
client_max_body_size 100m;
}
Reproduce it
curl -v -X POST -H 'Transfer-Encoding: chunked' -d 'hello' https://api.example.com/v1/events
# > Transfer-Encoding: chunked
# < HTTP/1.1 411 Length Required
Related
- 413 Content Too Large: body was too big rather than unsized.
- 400 Bad Request
- Content-Length and Transfer-Encoding
- 417 Expectation Failed: another upload-time refusal.
Frequently asked questions
What does 411 Length Required mean?
The server insists on knowing the size of the request body up front, via a Content-Length header, and your request did not provide one. This usually happens with Transfer-Encoding: chunked uploads or with POST/PUT requests that carry no body and no Content-Length: 0.
How do I fix 411 in curl?
For a POST with no body, send -d "" or -H "Content-Length: 0". For uploads, use --data-binary @file or -T file, which let curl compute the length, rather than piping from stdin, which makes curl fall back to chunked encoding.
Why do I get "POST requests require a Content-length header" from Google?
Google Frontend, which fronts Google Cloud services and many Google APIs, answers 411 with that text when a POST or PUT arrives with neither a body length nor chunked encoding, typically an empty POST sent without Content-Length: 0.
Does HTTP/2 need Content-Length?
No. HTTP/2 frames carry the data and mark the end of the stream, so there is no chunked encoding and a length header is optional. A 411 therefore points to an HTTP/1.1 hop, often a proxy or origin that is not HTTP/2-aware, converting the request.
Should my own API return 411?
Only if you cannot stream the body, for example because you must validate the size before accepting it. Otherwise rely on a body-size limit and return 413 when it is exceeded.
Sources
Related
417 Expectation Failed: Expect 100-continue
417 Expectation Failed means a server or proxy rejected your Expect header, usually Expect: 100-continue. Learn the causes and fixes for curl, .NET and Squid.
400 Bad Request
400 Bad Request means the server could not parse your request. Find which layer sent it, fix bad JSON and oversized cookies or headers, and reproduce with curl.
405 Method Not Allowed
405 Method Not Allowed means the URL exists but not for that method. Read the Allow header, then fix redirects turning POST into GET, static hosting and WAFs.
406 Not Acceptable
The server cannot produce a response matching the client's Accept headers. Learn about content negotiation and how to handle format mismatches.