HTTP 206 Partial Content

Partial Content

HTTP 206 is Partial Content: the server is answering a Range request with one or more parts of the representation instead of all of it (RFC 9110 section 15.3.7). A single part comes with a Content-Range header saying which bytes these are and how long the whole thing is; Content-Length counts only the bytes in this message.

The exchange

GET /videos/intro.mp4 HTTP/1.1
Range: bytes=0-1023

HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Range: bytes 0-1023/146515
Content-Length: 1024
Content-Type: video/mp4

Byte positions start at zero and are inclusive (RFC 9110 section 14.1.2), so 0-1023 is 1,024 bytes. bytes=500- asks for everything from offset 500, bytes=-500 for the last 500 bytes, and a last position past the end is trimmed to the end rather than refused.

Who asks for ranges

  • Video and audio elements. Browsers fetch media in ranges and seek by asking for new ones. Apple requires servers that host media for Safari on iOS to support byte-range requests.
  • Resumed downloads. Download managers, curl -C - and wget -c ask for the bytes they’re missing.

Resuming safely with If-Range

GET /files/backup.tar HTTP/1.1
Range: bytes=1048576-
If-Range: "v42"

If the ETag still matches, the server sends the rest as a 206. If the file changed, it ignores Range and sends the whole new file as a 200 (RFC 9110 section 13.2.2). Without it, a client can splice the end of one version onto the start of another; RFC 9110 allows combining parts only when they share the same strong validator.

Multiple ranges

Range: bytes=0-99,200-299 gets one 206 with Content-Type: multipart/byteranges; boundary=... and a Content-Range inside each part, never in the top-level headers (section 15.3.7.2). A server may merge overlapping ranges, and may ignore or reject a list of many overlapping or out-of-order ranges as a likely denial-of-service attempt; nginx’s max_ranges caps the count.

Caching

A 206 is heuristically cacheable. RFC 9111 lets a cache store partial responses and combine them into a complete one when they share a strong validator.

Gotchas

  • Range support is optional: a server may ignore Range and send a 200 with everything, so check the status before treating the body as a slice.
  • Accept-Ranges: bytes is advice, not a promise; Accept-Ranges: none asks clients not to try.
  • Ranges count bytes of the encoded content, so a gzip-compressed response is sliced after compression.

In your stack

nginx serves ranges for static files by default; max_ranges 0; turns them off. Express’s express.static and res.sendFile handle ranges (acceptRanges: false turns them off), as does Go’s http.ServeContent.

curl -r 0-1023 -o part.bin -D - https://example.com/videos/intro.mp4    # one range; headers on stdout
curl -C - -O https://example.com/files/backup.tar                       # resume where the file ends

Search 206 416 in the tool below to compare it with Range Not Satisfiable.

Try it in the HTTP Status Codes

206 Partial Content

  1. 206Partial Content2xx Success

    The body holds only part of the resource, as asked for with a Range header, and Content-Range says which part it is.

    When to use it

    Resumable downloads, video seeking, and parallel fetches of a large file.

    Common mistakes

    Sending it without Content-Range, or ignoring the range and answering with the whole file as a 200.

    Cacheable by defaultRFC 9110

Every code, by class

Codes marked unofficial come from one server’s own convention — nginx, Cloudflare, cPanel, Microsoft — and are not in the IANA registry.

Runs in your browser. Nothing you enter is sent anywhere.