206 Partial Content: what it means in your logs
·4 min read
A 206 Partial Content response means the client asked for part of a file with a Range header and the server sent back exactly that part. A 206 code is a success, not an error. In access logs it shows up almost entirely on video, audio, PDFs and large downloads, and most of the time it needs no fixing.
Look closer only when one IP pulls the same file in hundreds of slices, when 416 codes pile up, or when a crawler name asks for ranges of HTML pages. For the other codes, see the guide to HTTP status codes.
What is a 206 status code?
A 206 is the server's answer to a range request, defined in section 15.3.7 of RFC 9110. The client sends a Range header naming the bytes it wants, and the server replies with only those bytes plus a Content-Range header saying where they sit in the whole file.
GET /media/demo.mp4 HTTP/1.1
Range: bytes=0-1023
HTTP/1.1 206 Partial Content
Content-Type: video/mp4
Content-Length: 1024
Content-Range: bytes 0-1023/146515Content-Length here is the size of the slice, not the file. If the client asks for several ranges at once, the response type becomes multipart/byteranges and each part carries its own Content-Range, as MDN's 206 reference shows.
Range support is optional. RFC 9110 section 14.2 says a server MAY ignore the Range header, and GET is the only method the spec defines range handling for. A server that ignores it sends a normal 200 with the whole file. You can check what yours does with curl -I. Accept-Ranges: bytes means it supports ranges; Accept-Ranges: none, or no header at all, means it doesn't, per MDN's range requests guide.
Why you see 206 codes for video, PDFs and downloads
Clients that need only a piece of a big file send range requests. Three cases explain most 206 lines.
- Media players. A video or audio player fetches the start of the file, then asks for new byte ranges each time the viewer seeks. One play can leave dozens of 206 lines.
- PDF viewers and other large-file readers. They can ask for only the parts they need. MDN's own multipart example is a PDF.
- Download managers. A paused or dropped download resumes by asking for the remaining bytes. The client adds
If-Rangewith anETagor date, so if the file changed it gets a fresh 200 with the full file instead of a mismatched slice.
So counting 206 lines on a video overstates views. Count unique IP and file pairs per hour instead.
Do bots send range requests?
Some do, but HTML crawling rarely depends on them. Google's crawler overview handles large files differently. Its crawlers read the first 15MB of a file by default, a crawler like Googlebot may use a smaller limit such as 2MB, and anything past the limit is ignored. That page says nothing about range requests, so don't assume Googlebot sends them. Expect a long HTML page to log as 200.
Bots that fetch your media and PDFs may ask for ranges. Check the IP before trusting the user agent. Our log file analysis guide covers verifying a crawler by its published IP list.
When a 206 in your logs is normal vs a problem
Most 206 codes are fine. Here is how to sort the patterns.
| Pattern in the log | What it usually means | What to do |
|---|---|---|
Many 206s on .mp4, .mp3, .pdf from browser user agents |
Seeking, streaming, paged PDF views | Nothing |
| 206s from one IP on the same large file, all day | A download manager or scraper pulling the file in slices | Rate limit the IP if bandwidth hurts |
| 206 on an HTML page | A client asked for a range of a page, which is unusual | Check the user agent and IP |
| 416 Range Not Satisfiable | The client asked for bytes past the end of the file, often after you replaced it with a smaller one | Make sure the ETag changes when the file changes |
| Only 200s on large media, never 206 | Your server or CDN ignores Range, so every seek downloads the whole file |
Enable range support |
The last row costs money, and nobody reports it because nothing looks broken. Your bandwidth bill and slow seeking are the only signs.
How to read 206 codes by bot in server logs
Filter your log to status 206, then group by user agent. On an Apache or Nginx combined log, the status is the ninth space-separated field and the user agent is the sixth quoted field.
awk '$9 == 206' access.log | awk -F'"' '{print $6}' | sort | uniq -c | sort -rn | head -20Run it again with $7 in place of the user agent to see which files take the range requests. If a crawler name heads the list and the paths are HTML pages, verify the IP before you do anything. A request that claims to be GPTBot or ClaudeBot from an address its operator doesn't publish is an impostor, and the 206 is the least of it. The AI crawler list has the exact tokens if you decide to block one.
Check which bots fetch your files in your access log
The AI Bot Log Analyzer reads access log lines you paste (Apache or Nginx combined, JSON lines from Cloudflare Logpush, Vercel or Caddy, or W3C logs from IIS and CloudFront). It names each AI crawler and assistant, from GPTBot, ClaudeBot and PerplexityBot to ChatGPT-User, plus Googlebot and Bingbot, and checks each visit's IP against the list its operator publishes. Visits from an unlisted IP are flagged as impostors.
It treats a 206 like a 200, as a successful fetch, and does not count 206 codes separately. It lists the pages that returned errors such as 416, 404 or 5xx by status and bot, and counts 401, 403 and 429 as blocked requests. It does not connect to your server or CDN, and crawlers with no published IP list cannot be verified. Each run costs 8 credits.