Utilo

HTTP 406 Not Acceptable – Free, Online, Private

406 Not Acceptable means the server cannot produce a representation matching Accept.

What HTTP 406 means

406 says the resource exists and the server will not send a representation that fits the Accept headers. The client asked for a language, a charset, or a media type the server refuses to provide. The body may list what the server can send. Many APIs ignore Accept and return JSON anyway. If you honor Accept, 406 is how you say no.

406 Not Acceptable belongs to the 4xx client error class. Clients that only look at the class will group it with its neighbors. Clients that care about the exact code should use the narrower rule on this page, because the class is only the first digit.

When you see HTTP 406

When you see HTTP 406 Not Acceptable, stop on that exact status line. 406 Not Acceptable means the server cannot produce a representation matching Accept. The trace that usually produces it: Accept asked for XML and the API only speaks JSON. The 4xx client error class only tells you the first digit. A neighbor in that class is a different fault, and the fix on this page does not transfer to it.

Return 406 when content negotiation fails and you do not want to send a default. If a default is fine, send 200 in that default. Use 415 when the request body type is unsupported. Accept is about the response. Content-Type on the request is about the body you were sent.

How to fix HTTP 406

To fix HTTP 406, change the condition that made the server choose Not Acceptable. Change Accept to a type the server listed, or stop. Retrying the same Accept will fail. Do not treat 406 as a missing resource. Retry with a different Accept. An unchanged retry does nothing useful. If the log line is a different code, leave this page. The mix-up people make with 406 is this one: 415 is the request body's media type. 406 is the response the client is willing to accept. 300 offers a choice instead of refusing.

  • Accept-Language had no overlap with the translations you have.
  • A client sent Accept: */* and still got 406 because a gateway rewrote the header.
  • The server returned 406 with a body in a type the client had rejected, which the client then refused to parse.

An access log that only stores 406 is not enough to tell these apart. Keep the method, the path, and a request id. Do not keep the Authorization header or a request body that might be a token. The status explains the outcome. It is not a place to echo secrets back to the client either.

Example response

HTTP 406 Not AcceptableHTTP/1.1 406 Not Acceptable
Content-Type: application/json

{"available":["application/json"]}

The body is a hint, and it is itself a representation. There is a tension if the client rejected JSON. Prefer a short response in a widely understood type, or an empty body. The important fact is the status.

What the client should do

Change Accept to a type the server listed, or stop. Retrying the same Accept will fail. Do not treat 406 as a missing resource.

Vary on the request headers that caused the negotiation. A 406 cached without Vary can be served to a client that would have received 200.

Retry with a different Accept. An unchanged retry does nothing useful.

Codes people confuse with HTTP 406

415 is the request body's media type. 406 is the response the client is willing to accept. 300 offers a choice instead of refusing.

Frequently asked questions

Is 406 the same as 415?

No. 415 rejects the type of the request body. 406 rejects the types the client will accept in the response.

Should APIs always send 406?

Only if they actually negotiate. Ignoring Accept and returning JSON is a common, simpler contract.

What should the body contain?

A list of available representations, if you can say it in a type the client might read.

Does the resource exist?

Yes. The negotiation failed. A missing resource is 404.

What should I do first when I see HTTP 406?

Read the status as 406 Not Acceptable specifically. 406 Not Acceptable means the server cannot produce a representation matching Accept. Then check the cause that matches the request you sent, starting with: Accept asked for XML and the API only speaks JSON.