In the rich vocabulary of HTTP status codes, some codes stand out more than others while some quietly perform vital roles in ensuring smooth client-server communications. The 406 Not Acceptable status code is one such lesser-known hero. It might not appear as frequently as the popular 404 or 500, but understanding its purpose can dramatically improve your grasp of content negotiation and enhance the flexibility of your web applications and APIs.
The 406 Not Acceptable status code can feel like a cryptic message from your server. But once you understand what it means, it becomes a powerful signal that helps you design cleaner, more predictable, and more user-friendly APIs.
This status code represents a communication breakdown in the sophisticated dance of content negotiation process where clients and servers agree on the best format for data exchange.
In this blog post, we'll take a deep dive into what HTTP 406 Not Acceptable means, why it happens, how content negotiation influences it, and how you, as a developer or API consumer can deal with it effectively. Debugging weird errors like 406 Not Acceptable can be time-consuming without the right tools. That's why I recommend Apidog. It's a free, all-in-one API platform that lets you design, mock, test, debug and document APIs with ease so you'll know exactly why you're getting a 406 and how to fix it fast.
Now, let's explore the world of content negotiation and the HTTP 406 Not Acceptable status code.
The Problem: Everyone Wants Data Their Own Way
In the early days of the web, servers typically offered one format for their resources usually HTML. But as the web evolved, different clients emerged with different needs:
- Web browsers want HTML
- Mobile apps want JSON
- Other services might want XML
- Some clients might need PDF or CSV exports
The 406
status code exists because sometimes a client asks for a format that the server simply cannot provide for that particular resource.
What Does HTTP 406 Not Acceptable Actually Mean?
The 406 Not Acceptable
status code indicates that the server cannot produce a response matching the list of acceptable values defined in the request's proactive content negotiation headers, and that the server is unwilling to supply a default representation.
In simpler terms: "You've told me exactly what formats you'll accept, and I can't provide the resource in any of those formats."
A proper 406
response should include information about what formats the server can provide for the requested resource. This is typically done with headers or in the response body.
Here's what a 406
response might look like:
HTTP/1.1 406 Not AcceptableContent-Type: text/htmlVary: Accept
<html><head><title>406 Not Acceptable</title></head><body><h1>Not Acceptable</h1><p>This resource is available in the following formats:</p><ul><li>application/json</li><li>application/xml</li></ul></body></html>
For APIs, it's more helpful to return a structured response:
HTTP/1.1 406 Not AcceptableContent-Type: application/jsonVary: Accept
{
"error": "not_acceptable",
"message": "The requested resource is not available in the requested format.",
"available_formats": [
"application/json",
"application/xml"
]
}
It's not about whether the request is valid. It's about whether the response type is acceptable.
The Magic of Content Negotiation: How Accept Headers Work
To understand 406
, we need to understand how clients tell servers what formats they prefer. This happens through the Accept
header.
The Accept Header in Action
When a client makes a request, it can specify what content types it can handle and which ones it prefers:
A simple example:
GET /api/users/123 HTTP/1.1Accept: application/json
This says: "I want user data, and I only understand JSON."
A more sophisticated example:
GET /api/users/123 HTTP/1.1Accept: application/json, text/html;q=0.9, application/xml;q=0.8
This says: "I prefer JSON, but I can also handle HTML (with 90% preference) and XML (with 80% preference)."
The q
parameter (quality value) ranges from 0 to 1, with 1 being the most preferred.
When Negotiation Fails
A 406
error occurs when the server looks at the Accept
header and realizes:
- It has the resource the client wants
- It cannot provide it in any of the formats the client specified
- It's not willing to send a default format (like sending JSON to a client that only accepts XML)
How Does 406 Not Acceptable Fit Into Content Negotiation?
When a client sends an HTTP request including Accept
headers specifying acceptable media types (e.g., requesting JSON responses only), the server will attempt to deliver content accordingly.
If the server cannot provide any acceptable content that fits the criteria, it responds with:
textHTTP/1.1 406 Not Acceptable Content-Type: text/html
At this point, it means the server rejects the request because none of the available content representations match the client’s preferences.
Why Servers Return 406 Instead of 200 OK
You might think: why not just return something, even if it's not the preferred format?
Here's why servers return 406:
- To enforce strict content negotiation rules.
- To prevent sending data in a format the client explicitly said it cannot accept.
- To make debugging easier for developers by signaling mismatched
Accept
headers.
Common Causes of a 406 Response
Here are some typical reasons you'll see 406 Not Acceptable:
- Mismatched
Accept
headers → Client requestsapplication/xml
but the server only supportsapplication/json
. - Outdated API clients → Using older SDKs that expect different response formats.
- Improper server configuration → Content negotiation isn’t set up correctly.
- Framework quirks → Some frameworks (like Django or Rails) enforce strict
Accept
handling. - Custom error handling gone wrong → Overly strict filters on response formats.
Real-World Scenarios That Trigger 406 Errors
1. API Versioning Conflicts
Imagine an API that only serves JSON in its v2, but a client still expects XML from the v1 days:
GET /v2/products/456 HTTP/1.1Accept: application/xmlHTTP/1.1 406 Not AcceptableContent-Type: application/json
{
"error": "This API version only supports JSON",
"available_formats": ["application/json"]
}
2. Overly Restrictive Client Configuration
A mobile app might be hardcoded to only accept JSON, but encounters a server that only serves certain resources as XML:
GET /reports/quarterly-sales HTTP/1.1Accept: application/jsonHTTP/1.1 406 Not Acceptable
(The report might only be available as CSV or PDF)
3. Missing Default Fallback
Some servers are configured to be strict about content negotiation and refuse to guess what format to return when negotiation fails.
How Do Servers Usually Handle 406?
Interestingly, some servers ignore strict content negotiation and fallback to a default response rather than responding with 406.
However, strict RESTful APIs or services that emphasize precise communication might return 406 when client requirements cannot be met.
406 Not Acceptable vs Related Status Codes
To clarify 406's role, let's look at related HTTP statuses:
Status Code | Meaning | When to Use |
---|---|---|
400 Bad Request | Malformed syntax or invalid request | Request can’t be understood |
406 Not Acceptable | Valid request but server can’t fulfill accept headers | Content negotiation failure |
415 Unsupported Media Type | Server can’t process content type submitted by client | Invalid request body media |
406 vs 415 difference | 406 relates to response type, 415 relates to request body type | — |
How Should Clients Handle 406 Responses?
Clients receiving 406 should:
- Check the content negotiation headers they sent.
- Modify
Accept
headers to include broader media types. - Implement fallback mechanisms to request default formats (e.g.,
/*
). - Respect server capabilities and limit requests accordingly.
- Provide user-friendly messaging if specific content types can’t be served.
What Can Developers Do to Avoid or Handle 406?
- Offer multiple content representations (JSON, XML, HTML) where possible.
- Implement server-side negotiation logic to fall back gracefully rather than reject.
- Clearly document supported media types for API consumers.
- Log 406 responses to identify client incompatibilities or issues.
- Use libraries or frameworks with built-in content negotiation support.
Custom 406 Error Pages and Messages
For websites and APIs, serving meaningful and helpful 406 error responses improves the developer and user experience:
- Include suggestions on supported content types.
- Provide links or examples for correct usage.
- Use clear language in error messages.
- Stylize error pages consistent with the site branding.
Testing Content Negotiation with Apidog

Testing how your API handles different Accept
headers is crucial for building robust applications. Apidog makes this process straightforward and efficient.
With Apidog, you can:
- Easily Modify Headers: Quickly add and modify
Accept
headers to test how your server responds to different content type requests. - Test Multiple Formats: Create a collection of tests for the same endpoint with different
Accept
headers (JSON, XML, HTML) to ensure comprehensive coverage. - Validate 406 Responses: Intentionally send restrictive
Accept
headers to verify that your server returns proper406
responses with helpful error information. - Automate Content Negotiation Tests: Create test suites that automatically verify your API correctly handles various content type requests and returns appropriate status codes.
- Debug Complex Scenarios: Use Apidog's detailed logging to understand exactly why a
406
error occurred and what formats the server actually supports.
This systematic approach ensures your API can gracefully handle clients with different format requirements. In short: instead of fumbling in the dark, you know exactly what's acceptable. Download Apidog for free and boost your productivity in troubleshooting content negotiation and 406 scenarios.
Best Practices for Handling 406 Errors
For Server Developers:
- Provide Helpful Error Information: When returning a
406
, always include information about what formats you do support. This helps client developers fix their requests. - Use the Vary Header: Include a
Vary: Accept
header in your responses to indicate that the response content varies based on the Accept header. This helps caching systems work correctly. - Consider Default Behavior: While the HTTP spec allows servers to return a default representation, many modern APIs choose to be strict and return
406
to force clients to be explicit about their requirements. - Document Supported Formats: Clearly document what content types your API supports for each endpoint.
For Client Developers:
- Be Flexible in Accept Headers: Unless you have a specific reason, include multiple formats in your Accept header with appropriate quality values.
- Handle 406 Gracefully: When you receive a
406
, check the response for available formats and either adjust your request or show a helpful error message to the user. - Have Fallback Logic: Consider having fallback logic that can handle different formats if your primary preferred format isn't available.
The Unsung Hero of Content Negotiation
The Vary
header is crucial for proper caching behavior when content negotiation is involved. When a server includes Vary: Accept
in its response, it tells caches that the response content depends on the Accept header value.
This prevents a cache from incorrectly serving a JSON response to a client that requested XML, or vice versa.
Impact on SEO of 406 Responses
Generally, 406 does not affect SEO significantly because search engines usually handle content negotiation robustly and prefer valid responses. However, misconfigured APIs or websites that frequently return 406 can frustrate crawlers or users.
Modern API Design and 406
In modern RESTful API design, the use of 406
has evolved:
- Many APIs are JSON-only and don't bother with content negotiation, making
406
rare. - Versioning through URLs (e.g.,
/v1/
,/v2/
) has become more common than content negotiation for format changes. - Hypermedia APIs (HATEOAS) often use content negotiation to serve different representations of the same resource.
However, 406
remains relevant for:
- APIs that serve multiple data formats
- Content management systems that can output HTML, JSON, and XML
- Services that provide data exports in various formats
Troubleshooting 406 Errors
- Check client request headers for restrictive
Accept
values. - Review server's supported formats and negotiation logic.
- Use tools like Apidog to experiment with different header combinations.
- Adjust client or server configurations to widen accepted content options.
Security Considerations Around 406
- Prevents servers from leaking unintended formats.
- Helps avoid content-sniffing vulnerabilities.
- Can be configured to reject risky formats like
text/html
in APIs.
Conclusion: Embracing HTTP 406 Not Acceptable for Precise Communication
The HTTP 406 Not Acceptable
status code represents an important principle of web architecture: clear communication between clients and servers about their capabilities and requirements. It's not an error to be feared, but a mechanism for ensuring that data exchange happens in mutually understandable formats.
While you might not encounter 406
daily, understanding it makes you a better web citizen. It teaches the importance of being explicit about data format requirements and handling format negotiation gracefully.
For API developers, properly implementing content negotiation and 406
responses leads to more robust and flexible APIs. For client developers, understanding how to work with 406
errors ensures your applications can adapt to different server capabilities.
In a world where data needs to flow between diverse systems and platforms, the ability to negotiate content format is more valuable than ever. And when you need to test and perfect these negotiations, a tool like Apidog provides the perfect environment to ensure your applications communicate effectively, regardless of format preferences.