error code 406
HTTP 406 Error — Not Acceptable
HTTP 406 Not Acceptable is a client-error HTTP status code returned when a server cannot provide a representation of a requested resource that satisfies the client’s content-negotiation preferences. These preferences are commonly expressed through request headers such as Accept, Accept-Encoding, and Accept-Language.
A 406 is therefore usually not a problem with the URL itself. It is more often a mismatch between what the client says it can accept and what the server is able or willing to return.
Error message
A typical response looks like:
HTTP/1.1 406 Not Acceptable
Content-Type: application/json
{
"error": "Not Acceptable"
}
You may see variations such as:
406 Not Acceptable
HTTP Error 406 - Not Acceptable
Error 406: Not Acceptable
The requested resource is only capable of generating content
that is not acceptable according to the Accept headers sent
in the request.
The exact error page depends on the web server, reverse proxy, framework, API, CDN, or application generating the response.
What does HTTP 406 mean?
HTTP 406 Not Acceptable means:
The client requested a representation of a resource using certain content-negotiation preferences, but the server could not find an acceptable representation and chose not to provide a default one.
RFC 9110 defines 406 in terms of the resource’s available representation and the proactive negotiation headers supplied by the user agent.
For example, imagine an API supports:
application/json
text/html
but the client sends:
Accept: application/xml
If the server refuses to fall back to JSON or HTML, it may respond:
406 Not Acceptable
Simple explanation
Think of it like ordering food:
Client:
“Give me this resource, but only in XML.”
Server:
“I have JSON and HTML, but I don’t have XML.”
Server:
“I won’t give you another format.”
Result:
406 Not Acceptable
Why does HTTP 406 happen?
The most important concept behind 406 is content negotiation.
A client can tell a server what kinds of responses it prefers.
For example:
Accept: application/json
means:
I prefer JSON.
Or:
Accept: text/html
means:
I prefer HTML.
Or:
Accept: application/xml
means:
I prefer XML.
If the server cannot provide an acceptable representation and does not want to provide a fallback, it can return 406.
Common causes of HTTP 406
1. Incorrect Accept header
One of the most common technical causes is an Accept header that doesn’t match what the server supports.
Example:
Accept: application/xml
while the API only supports:
application/json
The server may return:
406 Not Acceptable
Fix
Try:
Accept: application/json
2. Unsupported response format
An API may support only certain representations.
For example:
Supported:
application/json
text/plain
but the client requests:
Accept: application/pdf
If PDF isn’t available for that resource, a 406 can result.
3. Accept-Language mismatch
Content negotiation can also involve language.
For example:
Accept-Language: fr-FR
but the server only has:
en
de
es
Depending on the server’s configuration, it could return 406 rather than selecting a fallback language.
Apache’s content-negotiation documentation specifically describes situations where language negotiation can result in 406.
4. Accept-Encoding mismatch
Clients can also specify supported content encodings.
Example:
Accept-Encoding: br
If the server has no acceptable representation according to its negotiation rules, it can potentially result in 406.
5. API client configuration
An application may unintentionally send an overly restrictive header.
For example:
headers: {
"Accept": "application/xml"
}
when the API expects JSON.
6. Web server content negotiation
Apache can use mod_negotiation to select among different representations of a resource.
If none of the available representations satisfy the client’s preferences, Apache can return 406.
7. Language configuration
A multilingual website might contain:
index.en.html
index.de.html
index.fr.html
If the request specifically accepts a language that isn’t available and the server is configured not to fall back, 406 can occur.
8. CMS or application security rules
This requires an important distinction:
Not every error page saying “406” is necessarily caused by standard HTTP content negotiation.
Some hosting environments, security modules, CMS plugins, WAFs, or application-level rules can generate a 406 response themselves.
For example, a security layer may reject a request and use:
406 Not Acceptable
as its chosen response status.
Therefore, when troubleshooting a 406, inspect the response headers and server logs rather than assuming the problem is always the Accept header.
Cloudflare, for example, notes that it does not generate 406 responses directly in the documented scenario; it can proxy a 406 returned by the origin server.
Quick fix
Try these fixes in order.
Fix 1 — Check the Accept header
Change:
Accept: application/xml
to:
Accept: application/json
if the API returns JSON.
Fix 2 — Remove unnecessary Accept headers
Instead of:
Accept: application/xml
try removing the header entirely.
Many servers will then choose their normal/default representation.
Fix 3 — Check Accept-Language
Try:
Accept-Language: en
instead of an unsupported language.
Fix 4 — Check API documentation
Find out which response formats the endpoint actually supports.
For example:
GET /api/users
Supported response:
application/json
Then use:
Accept: application/json
Fix 5 — Test with cURL
curl -i https://example.com/api/users
Then explicitly test JSON:
curl -i \
-H "Accept: application/json" \
https://example.com/api/users
Detailed fix
Step 1 — Inspect the request
Look at:
Request URL
Request Method
Accept
Accept-Encoding
Accept-Language
Content-Type
User-Agent
The most important headers for 406 troubleshooting are generally:
Accept
Accept-Encoding
Accept-Language
These are among the proactive content-negotiation headers identified by MDN and the HTTP specification.
Step 2 — Determine what the server supports
Suppose your API supports:
application/json
application/xml
Then these are reasonable:
Accept: application/json
or:
Accept: application/xml
But:
Accept: application/pdf
could produce 406 if PDF isn’t supported.
Step 3 — Check quality values
HTTP Accept headers can use quality values.
Example:
Accept: application/xml;q=1.0, application/json;q=0.8
This means:
XML → preferred
JSON → second preference
You can also use:
Accept: application/json, text/html;q=0.8, */*;q=0.5
The q value controls relative preference. RFC 9110 defines quality values for content negotiation.
Code examples
JavaScript — Fetch
Problem
fetch("/api/users", {
headers: {
"Accept": "application/xml"
}
});
If the API only supports JSON, this can cause:
406 Not Acceptable
Solution
fetch("/api/users", {
headers: {
"Accept": "application/json"
}
});
JavaScript — Axios
Problem
axios.get("/api/users", {
headers: {
Accept: "application/xml"
}
});
Solution
axios.get("/api/users", {
headers: {
Accept: "application/json"
}
});
Python — Requests
Problem
import requests
headers = {
"Accept": "application/xml"
}
response = requests.get(
"https://example.com/api/users",
headers=headers
)
print(response.status_code)
Possible result:
406
Solution
import requests
headers = {
"Accept": "application/json"
}
response = requests.get(
"https://example.com/api/users",
headers=headers
)
print(response.status_code)
print(response.json())
PHP — cURL
$ch = curl_init("https://example.com/api/users");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Accept: application/json"
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status;
echo $response;
Java — HttpClient
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/api/users"))
.header("Accept", "application/json")
.GET()
.build();
HttpResponse<String> response =
client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
System.out.println(response.statusCode());
System.out.println(response.body());
Swift — URLSession
For an iOS application:
var request = URLRequest(
url: URL(string: "https://example.com/api/users")!
)
request.httpMethod = "GET"
request.setValue(
"application/json",
forHTTPHeaderField: "Accept"
)
URLSession.shared.dataTask(with: request) {
data, response, error in
if let httpResponse = response as? HTTPURLResponse {
print(httpResponse.statusCode)
}
}.resume()
cURL examples
Test default behavior
curl -i https://example.com/api/users
Request JSON
curl -i \
-H "Accept: application/json" \
https://example.com/api/users
Request XML
curl -i \
-H "Accept: application/xml" \
https://example.com/api/users
Request an unsupported format
curl -i \
-H "Accept: application/pdf" \
https://example.com/api/users
If PDF isn’t available, this is a useful diagnostic test.
Apache example
Apache’s mod_negotiation can perform content negotiation.
For language negotiation, Apache supports directives such as:
LanguagePriority en fr de
Apache also provides:
ForceLanguagePriority Fallback
which can be used to provide a fallback rather than returning 406 when language negotiation cannot find an acceptable variant.
For example:
LanguagePriority en fr de
ForceLanguagePriority Fallback
This tells Apache to use a configured language fallback instead of returning 406 in the applicable negotiation scenario.
How to diagnose HTTP 406
A systematic diagnosis is much better than randomly changing server settings.
1. Open browser Developer Tools
In Chrome, Firefox, Edge, or Safari:
Developer Tools
↓
Network
↓
Failed request
↓
Headers
Check:
Request Headers
Response Headers
Status Code
Response Body
2. Check the Accept header
Look for:
Accept:
For example:
Accept: application/xml
Ask:
Does the server actually provide XML?
If not, try:
Accept: application/json
3. Check Accept-Language
Look for:
Accept-Language: es-MX
If the application only supports:
en
fr
de
the negotiation may fail depending on configuration.
4. Check Accept-Encoding
Look for:
Accept-Encoding: br
or:
Accept-Encoding: gzip
Check whether the server/proxy supports the requested encoding.
5. Compare a successful and failed request
This is one of the best debugging techniques.
Successful
GET /api/users HTTP/1.1
Accept: application/json
Failed
GET /api/users HTTP/1.1
Accept: application/xml
The difference immediately points toward content negotiation.
406 vs 400
| Error | Meaning |
|---|---|
| 400 Bad Request | Server cannot understand/process the request |
| 406 Not Acceptable | Server cannot provide an acceptable representation |
| 415 Unsupported Media Type | Request body format isn’t supported |
Example:
400 → Request itself is malformed
406 → Response format requested isn't acceptable
415 → Request body format isn't supported
406 vs 404
404 Not Found
The resource cannot be found.
406 Not Acceptable
The resource exists/was addressed, but the server
cannot provide an acceptable representation.
Therefore:
404 ≠ 406
Changing the URL is usually not the first thing to try for a genuine 406.
406 vs 405
405
Method Not Allowed
Example:
DELETE /api/users/10
when the endpoint only supports:
GET
POST
406
Not Acceptable
The method may be valid, but the requested representation isn’t acceptable.
RFC 9110 defines 405 as a method-related error and 406 as a representation/content-negotiation error.
406 vs 415
This is one of the most important distinctions for API developers.
406
Concerns the response.
Accept: application/xml
means:
Send me XML.
415
Concerns the request payload.
Content-Type: application/xml
means:
I’m sending XML to you.
So:
Accept → What response I want
Content-Type → What request data I am sending
A useful memory trick:
Accept = response preference
Content-Type = request body format
Platform/version differences
HTTP 406 is standardized by HTTP semantics, so its fundamental meaning does not change between operating systems.
However, how it is generated and displayed can differ considerably.
Apache
Apache can generate 406 through content negotiation, particularly through mod_negotiation.
Nginx
Nginx configurations, reverse proxies, upstream applications, and custom error handling can affect what the user sees.
PHP
PHP applications/frameworks can return 406 based on application-level content negotiation.
For example, a framework may inspect:
Accept: application/xml
and determine that XML isn’t available.
Node.js / Express
An API can implement its own response negotiation.
For example:
app.get("/users", (req, res) => {
if (req.accepts("json")) {
return res.json({
users: []
});
}
return res.status(406).send("Not Acceptable");
});
REST APIs
406 is particularly relevant to APIs because clients frequently specify:
Accept: application/json
or:
Accept: application/xml
CDNs and reverse proxies
A CDN may pass an origin-generated 406 back to the client. Cloudflare’s documentation specifically notes that its 406 handling can involve a 406 generated by the origin rather than Cloudflare itself.
Browser differences
Modern browsers support HTTP 406, but ordinary browser navigation rarely produces a visible 406 because browsers generally send broad Accept headers and servers often choose a reasonable default.
For example, a browser might send something resembling:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
The wildcard:
*/*
allows many response types.
This makes a browser less likely to trigger a strict content-negotiation 406 than a custom API client with an extremely restrictive Accept header.
Mobile application issues
A 406 can also appear in:
- iOS applications
- Android applications
- React Native
- Flutter
- Xamarin/.NET
- Java/Kotlin applications
- Swift applications
For mobile developers, check the HTTP headers generated by the networking library.
For example:
Accept: application/xml
might have been configured globally while the backend only returns JSON.
How developers should handle 406
A good API should return a useful response body.
For example:
{
"error": "not_acceptable",
"message": "The requested response format is not supported.",
"supported_formats": [
"application/json",
"text/html"
]
}
RFC 9110 recommends that a 406 response provide information about available representations from which the client can choose.
How to prevent HTTP 406
Client-side
Avoid unnecessarily restrictive headers.
Prefer:
Accept: application/json
when JSON is supported.
Avoid blindly setting:
Accept: application/xml
unless XML is actually required.
Server-side
Provide sensible fallback behavior where appropriate.
For example, instead of failing because the client requests an unsupported language:
fr-CA
the server could potentially fall back to:
fr
or:
en
depending on the application’s requirements.
Apache provides language-priority and fallback mechanisms for this type of scenario.
Real-world example
Imagine an API:
GET /api/products
supports:
application/json
The client sends:
GET /api/products HTTP/1.1
Host: example.com
Accept: application/xml
The server checks:
Requested:
application/xml
Available:
application/json
No acceptable representation exists.
If the server refuses to provide JSON as a fallback:
HTTP/1.1 406 Not Acceptable
The client should change its request to:
Accept: application/json
Then:
HTTP/1.1 200 OK
Content-Type: application/json
Another example — language
Suppose a website has:
English
Hindi
French
but a request says:
Accept-Language: ja
If Japanese isn’t available and the server is configured to strictly enforce the language preference:
406 Not Acceptable
A fallback configuration could instead select English.
Another example — API client
Incorrect
GET /customers/123
Accept: application/pdf
Server:
406 Not Acceptable
Correct
GET /customers/123
Accept: application/json
Server:
200 OK
Content-Type: application/json
SEO implications of HTTP 406
A 406 can become an SEO problem if it affects normal browser/crawler requests.
For example:
Googlebot
↓
Website
↓
406
If important URLs consistently return 406 to legitimate crawlers or users, the pages may become inaccessible.
However, do not automatically “fix” a 406 by disabling every security rule.
First determine whether:
- Content negotiation is failing.
- A WAF/security rule is returning the response.
- A CMS/plugin is generating it.
- An API is intentionally using 406.
- A reverse proxy is forwarding an origin response.
406 troubleshooting checklist
Use this checklist:
☐ Check HTTP status
☐ Check response body
☐ Check response headers
☐ Check Accept
☐ Check Accept-Language
☐ Check Accept-Encoding
☐ Check Content-Type
☐ Check API documentation
☐ Test with cURL
☐ Test without custom headers
☐ Test with application/json
☐ Check server logs
☐ Check Apache/Nginx configuration
☐ Check CMS plugins
☐ Check WAF/security rules
☐ Check reverse proxy/CDN
☐ Compare successful and failed requests
Developer diagnostic command
A useful first test is:
curl -v https://example.com/api/test
Then:
curl -v \
-H "Accept: application/json" \
https://example.com/api/test
Then compare the responses.
If the first request fails:
406
but the second succeeds:
200
you have strong evidence that the response negotiation or request headers are involved.
Important misconception
“406 means the website is down.”
Usually, no.
A 406 means the server responded but did not consider the requested representation acceptable.
It is a 4xx client-error status, not a 5xx server-error status. HTTP status codes in the 400–499 range represent client errors, while 500–599 represent server errors.
Important misconception: 406 vs firewall
“Every 406 is caused by a firewall.”
No.
The standardized meaning of 406 is content negotiation. However, applications or security layers can also deliberately use the 406 status for their own rejection behavior.
Therefore, always inspect:
Server
Via
CF-*
X-*
Response body
Application logs
Web-server logs
WAF logs
before deciding what generated the response.
Related errors
| Error | Name | Typical meaning |
|---|---|---|
| 400 | Bad Request | Invalid/malformed request |
| 401 | Unauthorized | Authentication required/failed |
| 403 | Forbidden | Server refuses access |
| 404 | Not Found | Resource not found |
| 405 | Method Not Allowed | HTTP method isn’t supported |
| 406 | Not Acceptable | No acceptable response representation |
| 407 | Proxy Authentication Required | Proxy authentication required |
| 408 | Request Timeout | Request timed out |
| 409 | Conflict | Request conflicts with current state |
| 410 | Gone | Resource is permanently unavailable |
| 411 | Length Required | Content-Length required |
| 412 | Precondition Failed | Request precondition failed |
| 413 | Content Too Large | Request body is too large |
| 414 | URI Too Long | URL is too long |
| 415 | Unsupported Media Type | Request format isn’t supported |
| 416 | Range Not Satisfiable | Requested range can’t be served |
| 417 | Expectation Failed | Expect header can’t be satisfied |
| 422 | Unprocessable Content | Request understood but semantically invalid |
| 429 | Too Many Requests | Rate limit exceeded |
406 vs 415 — remember this
This deserves special attention for developers:
406
↓
"I don't have a response format you can accept."
415
↓
"I don't understand the format you're sending me."
Example:
Accept: application/xml
can be relevant to:
406
while:
Content-Type: application/xml
can be relevant to:
415
Frequently asked questions
Is 406 a server error?
No. HTTP 406 belongs to the 4xx client-error class.
Is HTTP 406 caused by a bad URL?
Usually not. A 404 is much more directly associated with a missing resource.
Can changing the browser fix 406?
Sometimes, but it is generally better to identify the request header or server configuration responsible.
Is 406 common?
A strict, standards-based 406 is relatively uncommon on ordinary websites because servers can often provide a default representation instead. MDN notes that servers commonly choose to serve a representation rather than return 406.
Can an API return 406?
Yes. APIs are one of the places where 406 can be particularly meaningful because clients explicitly request response formats.
Can Apache return 406?
Yes. Apache’s content-negotiation functionality can return 406 when no acceptable representation is available.
Can Cloudflare cause a 406?
Cloudflare’s documentation says its service does not directly generate 406 in the documented scenario; it can proxy a 406 response from the origin.
Should I disable my firewall/WAF to fix 406?
No. First determine whether the 406 is generated by content negotiation, the application, the web server, or a security layer.
Ask / Analyze My Error
For a diagnostic tool such as WhatIsMyError.com, a useful 406 analyzer could ask the visitor to provide:
Error code:
406
Full error message:
[Paste error message]
URL:
[Enter URL]
Request method:
GET / POST / PUT / PATCH / DELETE
Accept:
[Enter Accept header]
Content-Type:
[Enter Content-Type]
Accept-Language:
[Enter Accept-Language]
Accept-Encoding:
[Enter Accept-Encoding]
Server:
Apache / Nginx / IIS / Node.js / Other
Framework:
PHP / Laravel / WordPress / Express / Django / Spring / Other
When does it happen?
[Browser / API / Mobile app / AJAX / cURL / Other]
Then the analyzer can produce:
Error
↓
406 Not Acceptable
Meaning
↓
The server cannot provide a response representation
that satisfies the client's content-negotiation preferences.
Likely cause
↓
Accept header mismatch
Recommended fix
↓
Try Accept: application/json
Next diagnostic step
↓
Compare the request with a successful request
and inspect the server/application logs.
That structure would fit particularly well with a WhatIsMyError.com article template because it gives both a beginner-friendly explanation and developer-focused diagnostics.
Short version
HTTP 406 Not Acceptable means:
The server could not provide a representation of the requested resource that matches the client’s content-negotiation preferences, and it did not choose to provide a default representation.
The first things to check are:
1. Accept
2. Accept-Language
3. Accept-Encoding
4. Supported API response formats
5. Server content negotiation
6. Application/framework logic
7. WAF/CDN/security rules
8. Server logs
For an API, the fastest test is often:
Accept: application/json
Discover more from what is my ERROR!
Subscribe to get the latest posts sent to your email.