# 411 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.

Source: https://howhttpworks.com/status-codes/411
Last reviewed: 2026-10-04

> **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 no `Content-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.

```http
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:

```text
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:

```bash
# 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
```

```python
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)
```

```javascript
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.

```nginx
location /uploads/ {
    proxy_pass http://legacy_backend;
    proxy_request_buffering on;   # default; buffers and sets Content-Length
    client_max_body_size 100m;
}
```

## Reproduce it

```bash
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](https://howhttpworks.com/status-codes/413): body was too big rather than unsized.
- [400 Bad Request](https://howhttpworks.com/status-codes/400)
- [Content-Length](https://howhttpworks.com/headers/content-length) and [Transfer-Encoding](https://howhttpworks.com/headers/transfer-encoding)
- [417 Expectation Failed](https://howhttpworks.com/status-codes/417): another upload-time refusal.
