Error code 406, “Not Acceptable,” means the requested resource has no current response representation that satisfies the preferences sent by the client, and the server will not send a default representation instead. The preferences can concern the response's media type, language, or encoding. That is the definition in HTTP Semantics, RFC 9110. It is about what the client can receive, not necessarily about the format of a request body it sends.
If you are visiting a site, a refresh or trying its normal URL once may help when the failure was temporary. If it persists, note the URL, time, and any request ID shown in the response, then contact the site operator. Do not disable browser security settings or repeatedly submit a purchase or form to test it. If you operate the service, capture the request preferences and identify the component that actually returned 406 before changing the client, application, proxy, or security policy.
What causes an HTTP 406 response?
HTTP calls a particular JSON document, HTML page, translated page, or compressed response a representation of a resource. In proactive content negotiation, a client can send request fields saying which representations it prefers. The server can choose a matching one. Depending on its policy, it may also send a default representation even when that does not match the stated preferences; 406 means it declined to do so. An absent preference field normally leaves the choice to the server, so do not invent a missing Accept header as the cause without evidence.
The main request fields to inspect are:
Accept: response media types, such asapplication/jsonortext/html. A client that accepts only JSON can receive 406 from an endpoint that only produces HTML and refuses a fallback. Quality values (q=) express preferences;q=0means that value is not acceptable. See the RFC's Accept definition.Accept-Language: preferred response languages, not the language of a request body. A server is not required to translate a resource merely because a client asks for another language. The RFC allows language negotiation but does not require every site to reject a request without a matching translation.Accept-Encoding: response content codings such asgzipandbr. Check whether an identity (uncompressed) response is acceptable under the actual header and whether a proxy modified compression behavior. The encoding rules have exceptions, so do not infer a mismatch solely from seeinggzipin the header.
Content-Type has a different job: on a request with a body, it describes the media type being sent to the server. A server that rejects that request format should generally use 415 Unsupported Media Type, not 406. Likewise, request Content-Encoding describes coding applied to the submitted body; it is not the same as the client's Accept-Encoding preference for the response. Our 415 guide covers that direction of the exchange in detail.
The status code alone does not prove which preference failed. It also does not prove that an origin application generated the response. An intermediary or a site-specific rule can return an HTTP status of its own. Treat a claim such as “the WAF blocked it” as a hypothesis until the relevant edge or application record identifies the rule and request. Cloudflare's 406 documentation describes the standard content-negotiation meaning; it does not make every 406 on a proxied site a Cloudflare security event.
How to diagnose a 406 without changing production settings
Start with one bounded, representative request. Record the time with timezone, method, host, route (without sensitive query values), status, and any request or edge ID. Keep the exact Accept, Accept-Language, and Accept-Encoding request fields, plus response Content-Type and Vary if present. Server, Via, and vendor-specific response headers can suggest the path a request took, but they do not by themselves establish which component made the decision. Do not copy Authorization, cookies, session identifiers, full URLs containing secrets, or private response bodies into a ticket or log.
For a public or otherwise safe GET endpoint, compare two declared response types. Replace the reserved example URL with a test resource you are authorized to query:
curl -i -H 'Accept: application/json' 'https://api.example.com/items'
curl -i -H 'Accept: text/html' 'https://api.example.com/items'
-i includes the response headers. These commands are diagnostic examples, not a promise that the example host returns 406. They may also print the response body, so use a non-sensitive fixture and avoid saving output to an insecure terminal transcript. Do not repeat a POST, payment, upload, or other state-changing request just to compare headers unless you have a safe test environment and know its idempotency behavior. A client library may add or override negotiation fields, so inspect the actual outbound request when a simple curl comparison differs from the failing client. The curl manual documents -i and -H.
Then work from the outside inward:
- Find the emitting hop. Correlate the response ID and time with CDN or gateway records, then with reverse-proxy and application access logs. A missing origin record can mean the request was rejected before the origin, but it can also mean logging is incomplete or indexed under another route. Check both possibilities.
- Compare the request with the endpoint's response contract. List what the route can actually produce for that method and version. If it produces only JSON while the client explicitly excludes JSON, the mismatch is concrete. Check quality values and wildcard ranges rather than looking only for one literal media type. If language or compression is implicated, compare the supported variants and any permitted default.
- Check where negotiation changed. A client update, API route change, gateway rewrite, framework response configuration, cache rule, or localization change can alter the effective request or available representations. If cached variants are involved, examine the response's
Varybehavior against the request fields the server used, as specified by RFC 9110. Do not assume a cache is at fault merely because a proxy exists. - Read the specific rejection evidence. Look for a route-level negotiation error, middleware decision, or a named gateway/security rule tied to this request ID. A custom WAF or proxy policy might choose 406, but that is an implementation choice, not the standard meaning of every 406.
If a response is 406 only for one browser locale, compare its Accept-Language with a successful request before changing global localization behavior. If it fails only for one API client version, compare the client's actual Accept field and route version. If every request fails after a deployment, check the deployed route's available response types and the exact hop that began emitting the status. These are investigation branches, not diagnoses by themselves.
Fix the mismatch at the component that owns it
Once you have a confirmed mismatch, make the smallest contract-correct change:
- Client: Send an
Acceptvalue for a response type the endpoint documents and the client can really parse. Do not setAccept: */*merely to suppress 406 if the client cannot safely handle every resulting type. If language is optional, offer realistic preferences or accept the documented default. - Application: Restore the intended representation, serialization, language variant, or documented fallback for that route. Returning HTML to a client that assumes JSON may turn a clear 406 into a parsing failure; test both status and response
Content-Type. - Gateway or cache: Remove an unintended header rewrite or fix variant caching after confirming it causes the mismatch. Preserve the application contract and test the direct and proxied paths separately.
- Security layer: If a named rule generated the response, inspect the rule's match and scope. Adjust an erroneous rule only through the site's approved change process and verify it still protects other traffic. Do not disable a WAF globally to make one 406 disappear.
Changes to clients, routes, gateways, or security rules are state-changing. Verify the failing request and at least one previously successful neighboring case after an approved change. For an API, assert the returned media type and parse the body in the same way the real client does. A status changing from 406 to 200 is not sufficient if the returned format is unusable.
406 versus other HTTP errors
A 406 concerns the response representation requested through proactive negotiation. A 415 concerns the format of the content sent in the request. A 404 says the target resource has no current representation or the server will not disclose one; it does not specifically describe a negotiation failure. A 403 is a refusal to fulfill the request, often used for access policy, though a particular vendor can choose a different status for its own rules. These meanings come from the HTTP status definitions.
Could the server have returned a default instead of 406? Yes. RFC 9110 permits a server to send a default when that is preferable to honoring the request's stated preferences strictly. That is a product and API contract decision, not a universal fix. A machine client that cannot parse the fallback may be better served by an explicit 406 with a useful, non-sensitive explanation of available representations.
Use logs to verify the diagnosis
Keep a compact, privacy-safe access event at the hop that knows the decision: timestamp, service and route, status, request ID, emitting component, an allowlisted summary of negotiation fields, and a reason or rule ID if available. Avoid logging complete headers, response bodies, credentials, or unbounded URLs. Compare the same request ID across edge, proxy, and application records. If you alert on a rise in 406 responses, use a rate with a consistent request denominator and account for low traffic; raw counts alone can mislead. The log-reading workflow helps separate recorded evidence from a theory about the root cause.
Fluxtail is a paid Starter/Pro, logs-focused destination for events already delivered through a supported collector or receiver. Its search, filters, and Live Tail can help inspect those records when the source emitted and mapped useful fields. It does not perform HTTP negotiation, automatically identify a WAF rule, or recover requests absent from upstream logs. Keep the original response and source records as evidence; use the central view to narrow the time, service, and request ID before changing the system that returned 406.