HTTP status code · Client errors (4xx)
406 Not Acceptable
406 Not Acceptable means the server cannot produce a response in any format, language or encoding that your Accept headers allow, and it chose not to send a default. It usually comes from an API client sending a strict Accept header, like Accept: application/xml to a JSON-only API.
| Class | 4xx, Client errors |
|---|---|
| Defined in | RFC 9110 §15.5.7 |
| Cacheable by default | Only with explicit Cache-Control or Expires |
| Safe to retry | Yes, with broader Accept, Accept-Language or Accept-Encoding headers |
| Relevant headers |
|
What 406 means
RFC 9110, section 15.5.7, ties 406 to proactive negotiation: the client lists what it can handle in Accept, Accept-Language and Accept-Encoding, and the server has no matching representation and is unwilling to supply a default. The server should list the available alternatives in the response body.
Most servers never send it for browsers. Browsers send Accept values ending in */*, and servers generally ignore unmatched preferences and return their default format, which the spec explicitly permits. The code shows up with strict API frameworks: Spring MVC, for example, throws HttpMediaTypeNotAcceptableException and answers 406 when no converter can produce the requested type. Some shared hosts also configure ModSecurity to answer blocked requests with 406, which has nothing to do with negotiation.
Common causes
If you are visiting the site
- A security module on the host (often ModSecurity) flagged something in the request, such as a form field or query string, and answers with 406.
If you run the server
- The client sends Accept: application/xml, text/csv or a vendor type the endpoint cannot produce.
- An endpoint that returns a file download is called with Accept: application/json by a generic HTTP client.
- Strict Accept-Language or Accept-Encoding with no wildcard, for example Accept-Encoding: br, identity;q=0 on a server without Brotli.
How to fix it
If you are visiting the site
- Remove unusual characters or code snippets from what you typed into the form and try again, then tell the site owner what triggered it.
If you run the server
- Send an Accept header the endpoint documents, or add */* with a lower q-value as a fallback (Accept: application/json, */*;q=0.8).
- On the server, prefer returning your default representation over 406 unless a wrong format would break the client.
- If ModSecurity is the source, find the rule ID in the audit log and tune or whitelist it for that path.
How to send 406
app.get('/reports/:id/export', (req, res) => {
res.status(406).json({ error: 'Not acceptable', available: ['application/json', 'text/csv'] });
});// app/reports/[id]/export/route.ts
export async function GET() {
return Response.json(
{ error: 'Not acceptable', available: ['application/json', 'text/csv'] },
{ status: 406 }
);
}mux.HandleFunc("GET /reports/{id}/export", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusNotAcceptable) // 406
w.Write([]byte(`{"error":"Not acceptable","available":["application/json","text/csv"]}`))
})from fastapi import FastAPI
from fastapi.responses import JSONResponse
app = FastAPI()
@app.get("/reports/{id}/export")
def export_report(id: str):
return JSONResponse(status_code=406, content={"error": "Not acceptable", "available": ["application/json", "text/csv"]})Commonly confused with
- 406 vs 415
- 415 is about the format of what the client sent (Content-Type); 406 is about the format the client wants back (Accept).
- 406 vs 300
- 300 Multiple Choices offers several representations to pick from; 406 says none of them fit what was asked for.
Frequently asked questions
- How do I fix a 406 Not Acceptable from an API?
- Check the Accept header your client sends. Set it to a type the API documents, usually application/json, or add */*;q=0.8 so the server can fall back to its default.
- Why do I get 406 on a WordPress or shared hosting site?
- Many shared hosts run ModSecurity with 406 as the response for blocked requests. It is a firewall match, not content negotiation, and the host can tell you which rule fired.
- Is 406 the same as 415?
- No. 415 Unsupported Media Type rejects the format of the request body, set by Content-Type. 406 rejects the formats the client asked to receive, set by Accept.
Last reviewed by Arielton Oberek.