API Design
HTTP 406 vs 415: Debug Content Negotiation
Resolve HTTP 406 and 415 errors by separating accepted response formats from request body types, then testing serialization and documented media contracts.
In this article
HTTP 406 vs 415: Debug Content Negotiation
An API request can contain valid JSON and still be rejected because the client and server disagree about media types. HTTP 406 concerns an acceptable response representation, while HTTP 415 concerns an unsupported request representation. Start by separating what you sent from what you asked to receive.
This is a targeted integration workflow, not a list of status-code definitions. Its purpose is to locate the representation mismatch across client serialization, headers, gateway behavior and endpoint documentation. The body and its declared media type must agree.
Distinguish Accept from Content-Type
Content-Type describes the representation carried by a message body. In a request, it tells the server how the submitted body is represented. Accept expresses which response media types the client can accept.
An illustrative JSON request uses:
Content-Type: application/json
Accept: application/jsonThese headers serve different directions of the exchange. Setting Accept does not turn a form-encoded body into JSON. Setting Content-Type does not serialize a JavaScript object for you.
The content-negotiation guide explains representation selection and related headers. APIs vary in how strictly they enforce requests, so check the endpoint's documented contract and actual behavior.
Capture the request that actually left the client
Inspect a synthetic request in the browser network panel or your API client's request view. Look at the outgoing headers and raw body. Don't rely only on the source code that was intended to build them.
A wrapper can add a header, serialize the body differently or remove a value. An SDK can send a vendor-specific media type where a handmade request sends generic JSON. Compare the final messages, not just the configuration options.
Use JSON Formatter on a synthetic JSON body to confirm syntax. That check cannot prove the client sent those same bytes or that the server accepts the chosen media type.
Diagnose a 415 from the input side
Compare the endpoint's accepted request types with the transmitted Content-Type. Check whether it expects JSON, a patch document, multipart form data or an entirely different representation.
Patch endpoints are a common trap: ordinary JSON, JSON Patch and JSON Merge Patch have different meanings and media types. See JSON Patch versus Merge Patch before changing a patch request to generic JSON just to avoid an error.
For multipart uploads, let the client library generate the boundary when it constructs the body. A manually assigned multipart header without the matching boundary can make a correctly assembled upload unreadable to the server.
Also inspect compression or content-encoding behavior when the server reports a representation problem. Don't assume the media type is the only characteristic being rejected.
Diagnose a 406 from the output side
Read the client's Accept value and compare it with the response types the endpoint can produce. A narrowly configured client may reject a representation that a normal browser accepts.
Try a documented supported response type in a controlled test. Preserve the production client's intended requirements rather than permanently broadening acceptance without reviewing what it can parse safely.
Some APIs use versioned vendor media types. A wrong or retired version in Accept can fail even when the body format is ordinary JSON. Review the API's migration documentation and any deprecation signals.
Compare a working reference request
Take the provider's supported example or a known working SDK call and reproduce it using synthetic data. Change one element at a time: body serializer, request media type, accepted response type or API version.
Keep authentication and resource selection constant so a permission failure doesn't confuse the experiment. If credentials differ between tests, record that fact explicitly.
Use Text Diff to compare sanitized raw request notes. Review headers case-insensitively while preserving values that carry semantic information. Remove authorization and cookies before sharing the comparison.
Check intermediary behavior
A gateway can route to a different endpoint version, add a response body or alter the error. Record whether the response came from the application, a proxy or an API gateway when that can be established safely.
The HTTP Header Checker can inspect public response headers, but it does not send your private authenticated POST body. Use it for public endpoint observations and use your integration client for the full failing exchange.
Don't assume a GET response predicts a POST endpoint's accepted input types. The same path can support different methods with different representation contracts.
Add regression fixtures
Preserve a successful supported request and a deliberately unsupported one. Confirm the unsupported request produces a clear error without partially applying a write. For a 406, check that clients handle the error body even when it differs from the success representation.
Test content-type parameters, empty bodies and the exact serializer used by the production client. Avoid a test that manually constructs perfect bytes while the application uses a different code path.
Document the accepted request media type and produced response media type in the endpoint contract. Include an example that shows both headers and the body rather than leaving the reader to combine separate fragments.
Conclusion
Debug 406 and 415 by treating request and response representation as separate contracts. Inspect the actual transmitted message, compare a working reference and test intermediaries carefully. Correct syntax matters, but correct serialization and declared media types make the integration work.