Variant Also Negotiates
ActiveHTTP 506 Variant Also Negotiates means the server's chosen variant is itself configured to engage in transparent content negotiation, creating an infinite negotiation loop. Defined in RFC 2295 §8.1. A server misconfiguration — one of the rarest HTTP status codes ever observed in production.
Description
The 506 Variant Also Negotiates status code indicates that the server has an internal configuration error. The chosen variant resource is itself configured to engage in transparent content negotiation, and is therefore not a proper end point in the negotiation process. This creates a circular reference that would result in infinite negotiation if the server attempted to resolve it.
Transparent Content Negotiation (TCN), defined in RFC 2295, allows a server to advertise multiple representations of a resource and let the client (or an intermediary) select the best variant based on capabilities and preferences. When the server selects a variant on behalf of the client, that variant must be a concrete resource — not another negotiable resource. A 506 signals that this invariant has been violated.
The analogy is straightforward: the server says 'I picked the best version for you,' but that version itself says 'well, I have multiple versions too — pick one,' which picks another version that also has versions. It's turtles all the way down. The negotiation can never terminate because there's no concrete resource at the end of the chain.
This is exclusively a server-side misconfiguration. The client did nothing wrong — it simply requested a resource, and the server's internal variant mapping is broken. The response SHOULD include an entity body describing the nature of the configuration error and the variants involved in the loop.
In practice, 506 is one of the most obscure HTTP status codes in existence. Transparent content negotiation per RFC 2295 was published as Experimental in 1998 and never achieved widespread adoption. Most modern servers use server-driven negotiation (the server picks based on Accept headers) or reactive negotiation (300 Multiple Choices) instead. Encountering a genuine 506 in the wild is exceedingly rare — it belongs to a specification that the web largely passed over.
Examples
GET /documents/report HTTP/1.1
Host: example.com
Accept-Language: en
Accept: text/html
Negotiate: transHTTP/1.1 506 Variant Also Negotiates
Content-Type: text/html
<html>
<head><title>506 Variant Also Negotiates</title></head>
<body>
<h1>Variant Also Negotiates</h1>
<p>The variant /documents/report.en selected for transparent content
negotiation is itself configured to negotiate, creating a loop.</p>
<p>Negotiation chain: /documents/report → /documents/report.en → /documents/report.en (negotiable)</p>
</body>
</html>GET /documents/report HTTP/1.1
Host: example.com
Negotiate: trans
--- Server internal variant map for /documents/report ---
URI: report.en; type="text/html"; language=en
URI: report.fr; type="text/html"; language=fr
--- But report.en ALSO has a variant map ---
URI: report.en-US; type="text/html"; language=en-US
URI: report.en-GB; type="text/html"; language=en-GB
--- And report.en-US ALSO negotiates → infinite loop → 506 ---# Misconfigured: /documents/report negotiates to report.en
# But report.en is ALSO configured as a type-map:
/documents/report.var:
URI: report.en; language=en
URI: report.fr; language=fr
/documents/report.en.var: ← THIS IS THE BUG
URI: report.en-US; language=en-US
URI: report.en-GB; language=en-GB
# The correct fix: report.en must be a concrete resource,
# not another negotiable type-map.# CORRECT: Only the top-level resource negotiates.
# Variants are concrete files, not negotiable resources.
/documents/report.var:
URI: report.en-US.html; language=en-US; type=text/html
URI: report.en-GB.html; language=en-GB; type=text/html
URI: report.fr.html; language=fr; type=text/html
# Each variant resolves to a CONCRETE file.
# No further negotiation. No 506.Edge Cases
- •506 is strictly a SERVER misconfiguration — the client cannot cause it and cannot fix it. Unlike 4xx codes, no amount of request modification will resolve a 506.
- •The negotiation loop may not be immediately obvious: /page → /page.en → /page.en-US → /page.en-US (negotiable) creates a chain that's only detectable at request time.
- •Servers MUST detect the loop and return 506 rather than entering an infinite internal redirect chain. Without loop detection, the server would hang or stack overflow.
- •A 506 response SHOULD include a body explaining the misconfiguration — specifically which variant was selected and why it cannot serve as an endpoint.
- •If a server doesn't implement TCN at all (most modern servers), it will never produce a 506 regardless of configuration — the code is specific to RFC 2295 negotiation.
- •Proxies and CDNs that cache variant selections may mask a 506 if they cached a valid response before the misconfiguration was introduced.
- •The Alternates header (RFC 2295 §8.3) in a 506 response can help administrators identify which variant triggered the loop by listing the problematic negotiation chain.
When You'll See This
- →Server configured with nested type-maps where a language variant itself has sub-variants that also negotiate
- →Apache mod_negotiation misconfiguration where a .var file points to another .var file instead of a concrete resource
- →Content management system generating variant maps dynamically without cycle detection in the variant graph
- →Migration from flat content structure to hierarchical variants introduces accidental negotiation loops
- →Automated deployment tool generates TCN configuration with circular references between locale-specific resources
- →Testing TCN implementation without proper termination conditions in the variant resolution algorithm
- →Documentation server attempting multi-dimensional negotiation (language × format × version) with improper variant hierarchy
Implementation References
| Language | Constant |
|---|---|
| Go | http.StatusVariantAlsoNegotiates |
| Rust | http::StatusCode::VARIANT_ALSO_NEGOTIATES |
| Python | http.HTTPStatus.VARIANT_ALSO_NEGOTIATES |
| Node.js | http.STATUS_CODES[506] |
| .NET | HttpStatusCode.VariantAlsoNegotiates |
| Java | 506 (no built-in constant — define custom) |
| PHP | Response::HTTP_VARIANT_ALSO_NEGOTIATES (Symfony) |
| Ruby | :variant_also_negotiates (Rack) |
History
Defined in RFC 2295 (Transparent Content Negotiation in HTTP), published as Experimental in March 1998 by Koen Holtman and Andrew Mutz. TCN was an ambitious attempt to let user agents participate in content negotiation by receiving a list of available variants and choosing the best one — rather than the server guessing based on Accept headers. The 506 code was defined to handle the specific failure mode where a variant selected during server-side choice (choice response, §10.2) is itself a negotiable resource, making the negotiation non-terminating. The RFC never advanced beyond Experimental status. Apache httpd had a mod_negotiation module that partially supported TCN and could theoretically produce 506 errors, but mainstream adoption never materialized. The web evolved toward server-driven negotiation (Accept + Vary headers) and client-side detection (responsive design, feature queries) instead. 506 remains registered in the IANA HTTP Status Code Registry but is effectively a historical curiosity — a solution to a problem that the web solved differently.
Related Status Codes
Related Headers
FAQ
What causes a 506 Variant Also Negotiates error?
A 506 occurs when the server uses Transparent Content Negotiation (RFC 2295) and the variant it selects for the client is itself configured to negotiate further. This creates an infinite loop: the server picks variant A, but A says 'I also have variants — pick one of mine,' and that pick also has variants, ad infinitum. It's always a server-side configuration error — specifically, a variant map that points to another negotiable resource instead of a concrete file. The fix is ensuring every variant in a type-map resolves to a terminal, non-negotiable resource.
Why is 506 so rare in production?
Transparent Content Negotiation (TCN) as defined in RFC 2295 was never widely adopted. The RFC remained Experimental and the web evolved toward simpler patterns: server-driven negotiation using Accept/Vary headers, reactive negotiation with 300 Multiple Choices, or client-side adaptation via responsive design and JavaScript feature detection. Since almost no production servers implement TCN, the specific failure mode that 506 represents (circular variant references) essentially cannot occur. Most developers will never encounter a genuine 506 in their entire career.
How is 506 different from 300 Multiple Choices or 406 Not Acceptable?
300 Multiple Choices is a SUCCESSFUL negotiation response — the server presents options and lets the client choose. 406 Not Acceptable means the server HAS concrete variants but none match the client's Accept headers. 506 is a SERVER ERROR — the negotiation process itself is broken due to circular references in the variant configuration. Think of it this way: 300 says 'here are your choices,' 406 says 'none of my versions work for you,' and 506 says 'my internal configuration is broken — I can't even finish figuring out what versions I have because they reference each other in a loop.'