HTTP 415 vs 406 — Unsupported Media Type vs Not Acceptable Comparison

http 415 vs 406: 415 is about Content-Type the client sent, 406 is about Accept the client wants. Learn the request vs response negotiation difference.

4xx

415

Unsupported Media Type

View full 415 page →

4xx

406

Not Acceptable

View full 406 page →

Quick Cheat Sheet

Aspect 415 Unsupported Media Type 406 Not Acceptable
About which header? Content-Type (request) Accept (request)
Direction Request body sent by client Response body the client wants
When? Server can't parse the body Server can't produce an acceptable representation

The Direction of Negotiation

This pair confuses developers because both relate to media types — but they sit on opposite sides of the request/response cycle.

415 Unsupported Media Type (RFC 9110 § 15.5.16): the client sent a request body (typically POST/PUT/PATCH) with a Content-Type the server doesn't understand. Example: posting text/csv to an endpoint that only accepts application/json.

406 Not Acceptable (RFC 9110 § 15.5.7): the client sent an Accept header listing only formats the server can't produce. Example: Accept: application/xml on a JSON-only API.

A Mnemonic

  • 415 = "Unsupported what you sent me"
  • 406 = "Not Acceptable what you want back"

Real-World Frequency

415 is common. Any modern API will return it if you forget Content-Type: application/json on a JSON POST, or send multipart/form-data to a JSON endpoint. Frameworks like Spring, Express+body-parser, FastAPI, and Rails all check this.

406 is rare. Most APIs serve only one or two formats and ignore Accept, returning 200 with their default representation regardless. This is technically against RFC, but in practice clients tolerate it. You'll see real 406 mostly in older XML-vs-JSON APIs and some Rails apps that explicitly call respond_to.

What About Charset?

Content-Type: application/json; charset=utf-16 should arguably return 415 if the server only handles UTF-8, though most parsers just attempt UTF-8 and fail with 400.

Best Practice

For 415, always include an Accept-Patch (for PATCH) or document the allowed Content-Types in the response body.

For 406, you can either return 406 strictly, or return your default representation with Vary: Accept and let the client deal with it. The pragmatic choice depends on your API consumers.

Adjacent Codes

  • 400 Bad Request is sometimes returned instead of 415 when the framework can't tell the difference between "wrong type" and "broken JSON."
  • 422 Unprocessable Entity is for when the type was right but the payload is semantically invalid.

Real-World Use Case

A FastAPI POST /users endpoint expecting JSON should return 415 if the request comes with Content-Type: text/plain, even before validation runs. For a content-negotiating Rails app with respond_to do |format|, missing format.html in an HTML-requesting context should return 406, prompting the client to request format.json instead.

Look Up Any Status Code

Browse all status codes →