Przejdź do treści głównej

Poradniki / Kody statusu HTTP wyjaśnione

406 Not Acceptable: what it means and how to fix it

A 406 Not Acceptable means the server cannot produce a response that matches what the client said it would accept. The request itself is fine; the negotiation between what was asked for and what the server is able to offer failed, usually over the format, language, or encoding of the response.

What 406 Not Acceptable means

HTTP supports content negotiation through a family of Accept headers: Accept for the response's media type, Accept-Language for the language, and Accept-Encoding for compression. A client can send any of these to say "only give me a response I can use." Per RFC 9110, if the server cannot produce a representation the client indicated it would accept, and it chooses to signal that rather than send something anyway, it answers 406. In practice, most servers quietly ignore a narrow Accept header and send their default response instead, which is why a genuine 406 is less common than the header itself.

How the error appears

A browser rarely triggers a 406 during normal page loads, because browsers send permissive Accept headers that match almost anything a server offers. It shows up far more often from API clients, scripts, and command-line tools that set a strict Accept header:

curl -i -H "Accept: application/xml" https://api.example.com/v1/status
HTTP/1.1 406 Not Acceptable
Content-Type: application/json

In that example the client asked only for XML and the API can only produce JSON, so the server declines rather than sending a format the client explicitly said it did not want.

What causes a 406 Not Acceptable

  • Content negotiation genuinely failing. An Accept, Accept-Language, or Accept-Encoding header naming only formats the server cannot produce, most often a client requesting XML from a JSON-only API, or a specific language variant the server does not have.
  • A web application firewall on shared hosting. This is a very common real-world cause that has nothing to do with content negotiation: ModSecurity and similar WAF rules on shared hosting environments block requests whose Accept header looks unusual, missing, or automated, and answer 406 as the block response regardless of what was being negotiated.
  • An API that only serves JSON, hit by a client sending Accept: text/html. Some APIs are strict about this and refuse rather than degrade, which surfaces as 406 for any client, including a browser tab opened directly on the endpoint.
  • A misconfigured reverse proxy or CDN rule that inspects and rejects based on the Accept header for caching or bot-filtering reasons, unrelated to what the origin server can produce.
  • Overly strict Accept-Encoding handling. A server configured to refuse any request that does not list a compression method it prefers, rather than falling back to an uncompressed response.

How to tell whose fault it is

If a specific script or integration is the only thing hitting 406, check what its Accept headers say, since a narrowed or misconfigured header on the client side is often the direct cause. If the same request works with a plain, permissive Accept header but fails with a specific one, the server genuinely cannot serve that format. If normal browser traffic is also affected, or the error started right after a hosting or WAF change with no code change on your side, shared-hosting security rules are the more likely culprit, and running an HTTP check from several locations with the exact headers your integration sends is the fastest way to confirm whether the block is consistent or specific to one network.

How to fix a 406 Not Acceptable

If you are a visitor

  1. Remove or relax the Accept header in whatever script or tool is making the request, if you control it, and let it accept the default format the server offers.
  2. Check the API's documentation for which content types and languages it supports before assuming the server is broken.
  3. Try the request from a browser directly, since browsers send broad Accept headers and rarely hit this error, which helps confirm the block is specific to your client's headers.

If you run the site

  1. Check your ModSecurity or WAF rules first if the 406 is unexpected and widespread, since shared hosting environments frequently block on Accept header patterns rather than genuine negotiation failure. Look at the WAF's own logs for the matched rule id before touching application code.
  2. Confirm what formats your API actually serves, and either support more of what real clients ask for or document the requirement clearly so a 406 is informative rather than surprising.
  3. Fall back to a default representation instead of refusing outright, where that is acceptable for your API, since most real-world clients handle "here is JSON even though you asked broadly" better than an outright rejection.
  4. Check reverse proxy and CDN rules for anything inspecting the Accept header for caching or bot management, since a rule meant for one purpose can produce 406 as a side effect for unrelated traffic.

How to prevent a 406 taking down an integration

A 406 introduced by a hosting provider's security update or a new WAF rule will not look like an outage from inside your own network, since your own requests may use different headers than an affected integration's. A scheduled HTTP check that sends the same Accept header your real clients use, with an assertion on the expected status code, catches a negotiation failure the moment it starts. Checking from multiple locations also helps separate a hosting-wide WAF rule from one that only applies at certain edge nodes.

See 403 Forbidden for the closely related case of a WAF or bot rule blocking a request outright rather than over content negotiation, the 4xx overview for the wider family, and 413 Payload Too Large elsewhere in this batch.

Frequently asked questions

Is 406 the same as a CORS error?

No. CORS failures happen because the browser refuses to expose a cross-origin response to the calling script; 406 is the server itself declining to produce a response body at all because it cannot satisfy the requested format, language, or encoding.

Why do I only see 406 from curl or Postman, never from the browser?

Browsers send broad, permissive Accept headers by default. Tools like curl send nothing or a narrow header unless you set one explicitly, which is far more likely to trigger a genuine negotiation failure or trip a WAF rule tuned to flag unusual headers.

Can a 406 come from ModSecurity even if my Accept header is completely normal?

Yes. Many shared-hosting ModSecurity rulesets flag requests as automated based on a combination of signals, including the exact structure and ordering of Accept headers, and answer 406 as a generic block response rather than because content negotiation actually failed.

Should my API return 406 or just default to JSON?

Defaulting to a sensible format is friendlier to real-world clients and is what most production APIs do. Returning 406 is defensible when serving the wrong format silently would be actively misleading to the caller.

What is the difference between 406 and 415?

406 is about what the client can accept in the response. 415 Unsupported Media Type is about what the server can accept in the request body the client sent. They cover opposite directions of the same negotiation idea.

Sprawdź teraz

Uruchom darmowe sprawdzenie na swojej stronie - bez zakładania konta.

HTTP check

Monitoruj to na stałe

Otrzymasz powiadomienie w chwili awarii: HostTracker sprawdza z ponad 300 lokalizacji i powiadamia e-mailem, SMS-em, przez Slack, Telegram i nie tylko.

Funkcje HostTracker

Więcej w tej sekcji: Kody statusu HTTP wyjaśnione