skip to content

What is the difference between HTTP status 406 Not Acceptable and HTTP status 415 Unsupported Media Type?

level: middleimportance: must knowfreq 54%

answer

  1. 406 = response side, Accept headers
  2. 415 = request side, Content-Type
  3. GET can 406, never 415
  4. 415 also fires on missing Content-Type
  5. malformed body = 400/422, not 415

basics

~20 s

406 is about the response: the server cannot produce any representation matching the request's Accept headers. 415 is about the request body: the server cannot process the Content-Type (or Content-Encoding) the client sent. Response side versus request side.

solid answer

~50 s

Both are 4xx negotiation failures, but they point in opposite directions. **406 Not Acceptable** — the *response* side. The client's `Accept`, `Accept-Language` or `Accept-Encoding` headers rule out every representation the server can produce. Nothing is wrong with what the client sent; the server simply has nothing acceptable to send back. A GET can return 406; a body is irrelevant to the decision. **415 Unsupported Media Type** — the *request body* side. The client sent a payload whose `Content-Type` (or `Content-Encoding`) the endpoint cannot handle: XML to a JSON-only endpoint, or no Content-Type at all. Only requests with a body — POST, PUT, PATCH — can produce it, and the fix belongs to the client's request, not its expectations. Memory hook: **406 = "I can't speak your language back to you"; 415 = "I can't read what you just handed me."** A useful third contrast: if the media type is right but the *content* is invalid, that is 400 or 422, not 415.

code

http · 7 lines
http
GET /users/42 HTTP/1.1
Accept: application/xml

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

{"title":"Not Acceptable","supported":["application/json"]}

go deeper

for a junior

State the direction clearly: 406 is about what comes back, 415 is about what you sent. One example each is enough.

for a middle

Add the trigger headers, that GET cannot yield 415, missing Content-Type as a 415 case, and the 400/422 boundary.

for a senior

Talk about recovery affordances (Accept-Post, problem+json listing supported types) and how your framework maps conditions to codes when reading production logs.

for a principal

Discuss consistency of error semantics across an API estate — one documented mapping for negotiation, syntax and semantic failures so clients can automate retries.

## Two directions of the same conversation An HTTP request negotiates on two independent axes: - What the client **can accept back** — `Accept`, `Accept-Language`, `Accept-Encoding`. - What the client **is sending now** — `Content-Type`, `Content-Encoding` on the request body. Each axis has its own failure code. ## 406 Not Acceptable — the response side Defined in RFC 9110: the target resource does not have a current representation acceptable according to the request's proactive negotiation header fields, and the server is unwilling to supply a default. Concretely: the client sends `Accept: application/xml`, the endpoint can only produce JSON, the intersection is empty. The request itself is perfectly well-formed. This can happen on a GET, a HEAD, or any method — a request body is not involved at all. A 406 response should tell the client what *is* available, ideally as a list of supported media types in the body (which is itself a small joke: you must pick some media type for that explanation, usually `application/problem+json` or `text/plain`). ## 415 Unsupported Media Type — the request side Also RFC 9110: the origin server is refusing to service the request because the payload is in a format not supported by this method on this target resource. Triggers: - `Content-Type: application/xml` sent to a JSON-only endpoint. - **No `Content-Type` at all** on a request with a body — the server cannot guess, and guessing is a security hazard. - An unsupported `Content-Encoding` on the request body, e.g. a client gzips its POST body and the server cannot decompress it. - A media type the endpoint supports generally but not for this method (`multipart/form-data` fine on the upload endpoint, meaningless on this one). A 415 **should** carry an `Accept-Post` (or `Accept-Patch` for PATCH) response header naming the media types the endpoint will take, so the client knows how to retry. ## The comparison, sharply | | 406 | 415 | |---|---|---| | Concerns | the response representation | the request body | | Triggered by | `Accept*` request headers | `Content-Type` / `Content-Encoding` of the body | | Possible on GET | yes | no (no body) | | Client fixes it by | asking for a type you produce | sending a body/type you accept | | Helpful response header | list alternatives in the body | `Accept-Post` / `Accept-Patch` | ## The neighbouring codes you must not confuse - **400 Bad Request** — the body is the right media type but malformed (broken JSON syntax). - **422 Unprocessable Content** — the body parses as the declared type but is semantically wrong (valid JSON, missing a required field, invalid email). Many APIs use 400 here instead; either is defensible, but 415 is not, because the *media type* was fine. - **404 / 405** — the resource or method is wrong; nothing to do with representation. A clean rule: **415 = I can't parse this at all because I don't know the format. 400 = I know the format, it's broken. 422 = it parses, it's wrong.** ## Why interviewers ask this It is a compact test of whether you actually think in terms of request versus response and of whether you reach for status codes with precision. The frequent wrong answer is that 415 means "unsupported Accept header" — reversing the two — or that a JSON body missing a required field warrants 415. In practice frameworks emit these for you: a Spring or ASP.NET controller declaring it consumes JSON returns 415 automatically for an XML body, and returns 406 when no configured message converter can satisfy the Accept header. Knowing which condition your framework maps to which code is the difference between reading a production log correctly and guessing.

  • Can a GET request ever produce 415?
    Essentially never, because a GET has no body for the server to refuse. 415 is about the payload's media type, so it belongs to POST, PUT and PATCH. If a GET is failing, the negotiation-related candidate is 406; more often the real answer is 404, 405 or 400.
  • A client POSTs syntactically valid JSON with Content-Type: application/json, but a required field is missing. Which status?
    Not 415 — the media type was understood and parsed. Use 422 Unprocessable Content for a semantically invalid document, or 400 Bad Request if your API uses that for all validation failures. 415 would tell the client to change its Content-Type, which would be misleading.
  • What response header helps a client recover from a 415?
    `Accept-Post` on a POST (or `Accept-Patch` for PATCH) lists the media types the endpoint will accept for a body, so the client can retry correctly instead of guessing. Including the supported types in a problem-detail body as well is good practice.

406 is a restaurant that has no dish you can eat. 415 is the kitchen refusing the ingredients you brought in, because it cannot tell what they are.

saying these in an interview costs you the question

  • Reversing them — saying 415 is about the Accept header.
  • Returning 415 for a well-formed JSON body that fails validation.
  • Claiming a GET can return 415.
  • Thinking 406 means the client sent a bad request rather than that the server has nothing acceptable.
  • Returning 400 for every negotiation failure because 'it's all client error anyway'.

context