406 Not Acceptable 4xx
The server cannot produce a response matching the content characteristics requested by the client.
What does 406 mean?
A 406 Not Acceptable response means the server can't produce a response that matches the content characteristics the client said it would accept — specified via headers like Accept, Accept-Language, Accept-Encoding, or Accept-Charset. This is part of HTTP's content negotiation mechanism, where a client can express preferences about the format of the response (JSON vs XML, English vs French, gzip vs uncompressed, etc.), and 406 is what happens when the server simply can't satisfy any of those preferences.
In practice, 406 is one of the rarer 4xx codes — most servers are flexible enough to return something reasonable even if it's not the client's first preference, rather than failing outright with 406.
How a 406 behaves
- It's triggered by
Accept-*headers, not the request body or URL — the request itself might be perfectly fine; it's specifically about what format the response should take - It can carry a body listing the formats the server can provide, even though none match what was requested
- It's not cacheable in a generally meaningful way, since it depends on request-specific
Acceptheaders - It's distinct from 415 — 406 is about what the client is willing to receive (the response), while 415 is about what the client sent (the request body) being in an unsupported format
Common causes
If you're building the API:
- A client sent an
Acceptheader requesting a format your API doesn't support (e.g.,Accept: application/xmlwhen your API only returns JSON), and you've implemented strict content negotiation that returns 406 rather than ignoring the header and returning your default format - A client requested a language via
Accept-Languagethat your API doesn't have content for, and strict negotiation is enabled
If you're calling an API:
- Your
Acceptheader is too restrictive — e.g., explicitly requestingapplication/xmlfrom an API that only produces JSON - An overly specific
Accept-LanguageorAccept-Charsetheader doesn't match anything the server supports
If you're a website visitor:
- Essentially never encountered directly — content negotiation for web pages is almost always handled gracefully by browsers and servers without surfacing 406 to users
How to fix it
As an API/website builder:
- Consider whether strict 406 responses are actually beneficial — many APIs choose to ignore an unsupported
Acceptheader and return their default format (with aContent-Typereflecting what was actually sent) rather than failing the request entirely with 406 - If you do implement strict content negotiation, make sure your API documentation clearly lists supported
Acceptvalues - For
Accept-Language, consider falling back to a default language rather than returning 406 when a requested language isn't available — a response in an unexpected-but-readable language is often more useful than no response at all
As an API consumer:
- Loosen your
Acceptheader — if you can work with multiple formats, list them in order of preference rather than specifying only one (e.g.,Accept: application/json, application/xml;q=0.9) - Check the API's documentation for exactly which formats/languages/encodings it supports, and align your request headers accordingly
- If a 406 response includes a body listing supported formats, use that to adjust your request
As a website visitor:
- Not applicable — this isn't something end users encounter or fix directly
406 vs 415
| 406 Not Acceptable | 415 Unsupported Media Type | |
|---|---|---|
| What it's about | The format the client is willing to receive (response) | The format of what the client sent (request body) |
| Relevant header | Accept (and related Accept-* headers) |
Content-Type |
| Direction | Server → Client (response format negotiation) | Client → Server (request body format) |
Real-world examples
406 is genuinely rare in practice — most well-designed APIs prefer to be permissive about Accept headers, returning their standard format (typically JSON for modern APIs) regardless of what was requested, rather than failing the request entirely. When 406 is implemented, it's often in APIs that support multiple genuinely different response formats (e.g., both JSON and XML for legacy compatibility) and want clients to be explicit about which they need.
SEO implications
406 is essentially never relevant to page-level SEO — search engine crawlers send standard Accept headers that virtually all servers can satisfy, and content negotiation failures of this kind don't occur in normal web crawling.
FAQ
What's the difference between 406 and 415?
406 is about the format the client is willing to receive in the response (controlled by Accept headers). 415 is about the format of what the client sent in the request body (indicated by Content-Type). They're opposite directions of the same general "format" concern.
Why is 406 so rarely seen?
Most APIs and servers prefer to be lenient — if a client requests a format the server doesn't support, many servers simply return their default format anyway (with an accurate Content-Type header) rather than failing the entire request. Strict 406 enforcement is a deliberate, less common design choice.
How do I avoid getting 406 errors?
Make your Accept header less restrictive — include multiple acceptable formats with relative preferences (using q values), or omit the Accept header entirely if you're flexible about the response format, letting the server use its default.
Is 406 related to language negotiation too?
Yes — content negotiation covers more than just data format (Accept); it also includes language (Accept-Language), character encoding (Accept-Charset), and compression (Accept-Encoding). A 406 can theoretically result from a mismatch on any of these, though format mismatches are the most commonly discussed case.
Can I just ignore 406 and assume my request worked?
No — 406 means the server explicitly declined to produce a response in any format you indicated as acceptable. Unlike some "soft" issues, this is a real rejection of the request as specified; you'll need to adjust your Accept headers and resend the request to get a usable response.
Fun fact
406 is part of a small family of status codes (along with 415) entirely dedicated to the concept of content negotiation — a feature of HTTP that's been part of the protocol since very early on, but that the vast majority of modern web traffic barely uses beyond basic compression negotiation (Accept-Encoding: gzip), making 406 something of a relic of a more format-diverse vision of the web that didn't fully materialize in practice.