406 Not acceptable: what it means and how to fix it

A clear guide to understanding HTTP 406 Not Acceptable and practical steps to diagnose and resolve it.
HTTP 406 Not Acceptable is one of those HTTP status codes that sounds technical but is actually about a simple idea: the client asked for a response in a format the server can’t provide. When you see 406, the server is saying, In this context, I can’t deliver a response that matches your Accept header or other negotiation criteria. This article walks through what 406 means, common causes, how to diagnose it, and practical fixes for developers, sysadmins, and site owners.
What does 406 Not Acceptable mean?
406 is a client error response status code. It falls under the broader umbrella of HTTP content negotiation, where the client and server negotiate the best representation of a resource. The Accept header in the request tells the server which media types the client can handle (for example, text/html, application/json, image/png, etc.). If the server cannot generate any representation that satisfies those constraints, it returns 406.
Key ideas:
- It’s about representation, not the resource being missing.
- It can target the whole response (the body) or parts of it (headers, language, encoding).
- It often indicates a mismatch between what the client asks for and what the server can deliver.
Common causes of 406 Not Acceptable
Content negotiation limits on the server
- The server is configured to support a narrow set of content types.
- Requested content types by the client are not among the server’s supported types.
- Dynamic systems (APIs, CMSs) may only serve certain formats for certain endpoints.
Accept header problems on the client
- The client sends Accept: / but expects a very specific representation elsewhere.
- Quality values (q factors) order preferences that the server cannot meet.
- The request includes multiple Accept-* headers (like Accept-Language) with combinations the server does not support.
Proxies, gateways, or reverse proxies
- A proxy might rewrite headers or block certain content types.
- Caching layers may serve a cached 406 from a previous, mismatched negotiation.
- Load balancers could route requests to endpoints that don’t support the requested formats.
Misconfigurations or software bugs
- Middleware in web frameworks incorrectly handling content negotiation.
- Custom error handlers returning 406 for requests they cannot fulfill due to business logic.
- Legacy code paths that only support a subset of content types.
Security or access-related restrictions
- Some APIs return 406 when a user is not authorized to access certain representations.
- Content negotiation could be gated behind authentication or scopes.
Examples of typical 406 scenarios
- A client requests Accept: application/json, but the endpoint only serves text/html.
- An API endpoint that normally returns JSON is invoked with Accept: application/xml and the server has no XML serializer.
- A static file server configured to deliver only text/html and image/png, but the request asks for application/pdf.
How to diagnose 406 Not Acceptable
Reproduce with a minimal request
- Use curl or a simple HTTP client to reproduce the request with clear Accept headers.
- Example: curl -i -H "Accept: application/json" https://example.com/resource
- If the same request works with Accept: text/html but not application/json, you’re narrowing the problem to content negotiation.
Check server logs
- Look for messages around content negotiation, serializer selection, or middleware decisions.
- Logs may show what representations were attempted and why none were selected.
Inspect proxies and gateways
- Check any reverse proxies (Nginx, Apache proxy, HAProxy) for how they pass Accept headers.
- Review cache entries that might be serving stale or incompatible representations.
Test endpoints with varied Accept headers
- Try Accept: / and Accept: text/html, Accept: application/json, Accept: application/xml.
- If one format consistently works, focus on why others aren’t supported by the endpoint.
Review API documentation and server capabilities
- Confirm which content types are officially supported for each endpoint.
- Some endpoints may only support a subset (e.g., JSON for certain APIs, HTML for web pages).
Check for language and encoding negotiation
- 406 can occur if Accept-Language, Accept-Charset, or Accept-Encoding negotiations fail.
- Ensure the server can respond with the requested language or encoding.
Examine authentication and authorization impact
- Some servers return 406 when a user lacks permission to view certain representations.
- Verify whether authentication state changes the available representations.
Practical fixes: server-side, client-side, and infrastructure
If you’re a developer implementing the API or web app
- Align content negotiation with your capabilities:
- Implement serializers for the most common Accept headers your clients use.
- Provide a sensible default (e.g., JSON) when the client’s preferences can’t be matched.
- Avoid returning 406 unless truly necessary. Consider 415 (Unsupported Media Type) if the client sends an content-type the server can’t handle.
- Improve error messages:
- Return a 406 with a clear body explaining which representations are supported.
- Include an Accept header example or a list of supported content types.
- Review middleware order:
- Ensure your routing, authentication, and content negotiation logic run in predictable order.
- Place content negotiation early in the request lifecycle so you can fail fast with a helpful message.
If you’re configuring a web server or gateway
- Nginx example: ensure the server block doesn’t aggressively reject unknown types and that try_files or rewrite rules don’t trigger unexpected negotiation outcomes.
- Apache example: enable proper content negotiation modules only where needed and ensure MultiViews is configured intentionally (it can trigger 406 in some setups).
- Reverse proxies:
- Pass through Accept headers without modification.
- Disable or correctly configure any response rewriting that could alter the negotiation results.
- Caching:
- Purge caches when you deploy new representations.
- Avoid serving stale 406 responses by invalidating relevant cache keys when underlying content-type availability changes.
If you’re debugging client behavior
- Normalize Accept headers during testing:
- Start with Accept: application/json, text/html. Q=0.9, /. Q=0.1 to expose negotiation issues.
- Use robust error handling:
- If you receive 406, attempt a safe fallback (e.g., try a different Accept value or request a known good format).
- Update client libraries or SDKs:
- If a framework’s HTTP client has bugs around content negotiation, upgrade or patch to a known fix.
If you’re troubleshooting at the infrastructure level
- Check load balancers and API gateways for customization:
- Ensure they don’t translate Accept headers in a way that makes back-end services unable to respond in the requested format.
- Audit caching layers:
- Confirm that cached responses are consistent with the current negotiation capabilities.
- Review security devices:
- Some WAFs or API security tools might block certain content types. Verify rules and exemptions.
A quick comparison: 406 versus similar status codes
| Status code | Meaning in brief | When it’s triggered | Typical user impact |
|---|---|---|---|
| 406 Not Acceptable | Server cannot provide a representation matching the request’s Accept headers | Content negotiation constraints | User may see a page or API error; message usually points to supported types |
| 415 Unsupported Media Type | The request entity’s type is not supported by the server (often in POST/PUT) | Client sends a disallowed Content-Type | Client must resend with a supported media type |
| 400 Bad Request | The request is malformed or invalid | Syntax errors, missing required fields | Client should fix request structure or data |
| 415 vs 406 distinction | 415 is about request body type; 406 is about response content types | Different negotiation axes | Helps pinpoint whether issue is input vs. output capabilities |
Best practices for preventing 406 in production
- Define and document a clear set of supported representations for each endpoint.
- Prefer returning a discoverable error when negotiation fails, not a generic 406:
- Include a list of supported formats.
- Offer a default format automatically if possible.
- Keep a simple, predictable negotiation policy:
- Favor a single default (e.g., application/json) for APIs.
- Use content negotiation sparingly in public-facing web apps where users expect HTML.
- Monitor for 406 spikes:
- Set up alerts if 406 errors rise above baseline, indicating a misconfiguration or recently changed capabilities.
- Test with real-world clients:
- Include automated tests that simulate common Accept header scenarios, proxies, and caching layers.
Short final section: the recommendation
If you encounter 406 Not Acceptable, start with a focused diagnosis of content negotiation:
- Confirm which representations your server actually supports for the affected endpoint.
- Reproduce with controlled Accept headers to isolate whether the issue is client-side, server-side, or infrastructure-related.
- Check proxies, gateways, and caches that might alter negotiation results.
- Align your client and server capabilities: either broaden the server’s supported representations, narrow the client’s requests, or implement a clear default fallback.
- Improve error messaging to help future debugging: a concise 406 response that lists supported content types is often the fastest path to a long-term fix.
By following these steps, you can identify whether the problem is a simple mismatch in formats, a misconfiguration in a reverse proxy, or a deeper issue in your API’s content negotiation logic, and you’ll be better equipped to deploy a robust, user-friendly solution.
