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

ErrorMeaning
400 Bad RequestServer cannot understand/process the request
406 Not AcceptableServer cannot provide an acceptable representation
415 Unsupported Media TypeRequest 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:

  1. Content negotiation is failing.
  2. A WAF/security rule is returning the response.
  3. A CMS/plugin is generating it.
  4. An API is intentionally using 406.
  5. 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

ErrorNameTypical meaning
400Bad RequestInvalid/malformed request
401UnauthorizedAuthentication required/failed
403ForbiddenServer refuses access
404Not FoundResource not found
405Method Not AllowedHTTP method isn’t supported
406Not AcceptableNo acceptable response representation
407Proxy Authentication RequiredProxy authentication required
408Request TimeoutRequest timed out
409ConflictRequest conflicts with current state
410GoneResource is permanently unavailable
411Length RequiredContent-Length required
412Precondition FailedRequest precondition failed
413Content Too LargeRequest body is too large
414URI Too LongURL is too long
415Unsupported Media TypeRequest format isn’t supported
416Range Not SatisfiableRequested range can’t be served
417Expectation FailedExpect header can’t be satisfied
422Unprocessable ContentRequest understood but semantically invalid
429Too Many RequestsRate 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.