HTTP
506 - Variant Also Negotiates
Getting a 506 Variant Also Negotiates means the server has a configuration error where a variant resource is trying to negotiate its own content, creating a negotiation loop. This server-side error (5xx) indicates an internal server misconfiguration, not a client problem. Most common when content negotiation is misconfigured, but also appears when variant resources are set up incorrectly, negotiation loops occur, or server configuration conflicts create recursive negotiation.
#Common Causes
- →Frontend: Client can't fix 506s directly—this is a server configuration issue. Requests trigger server's negotiation loop. Content negotiation headers may expose the issue.
- →Backend: Server content negotiation misconfigured. Variant resource tries to negotiate itself. Negotiation loop detected. Server configuration conflict. Content negotiation middleware error.
- →Infrastructure: Web server content negotiation misconfiguration. Reverse proxy negotiation conflicts. CDN variant handling errors.
✓Solutions
- 1Step 1: Diagnose - Check DevTools Network tab—506 responses indicate server misconfiguration. Review Accept headers sent. Check if content negotiation is involved.
- 2Step 2: Diagnose - Server logs show negotiation loop details. Review content negotiation configuration. Check variant resource setup. Examine server configuration files.
- 3Step 3: Fix - Client-side: Simplify Accept headers to avoid triggering negotiation. Use specific content types. Retry with simpler headers.
- 4Step 4: Fix - Server-side: Fix content negotiation configuration. Remove recursive variant negotiation. Configure variants properly. Test negotiation logic.
- 5Step 5: Fix - Infrastructure: Review web server negotiation settings. Fix reverse proxy configuration. Update CDN variant handling.
</>Code Examples
Fetch API: Handle 506 with Simplified Headers
1// Client-side: Handle 506 by simplifying content negotiation
2async function fetchResourceWithFallback() {
3 // Try with full content negotiation first
4 let response = await fetch('/api/resource', {
5 headers: {
6 'Accept': 'application/json, application/xml;q=0.9',
7 'Accept-Language': 'en-US, en;q=0.9',
8 'Accept-Encoding': 'gzip, deflate',
9 },
10 });
11
12 if (response.status === 506) {
13 console.warn('Variant negotiation error - server misconfiguration detected');
14
15 // Fallback to simpler Accept header (no variants)
16 response = await fetch('/api/resource', {
17 headers: {
18 'Accept': 'application/json', // Single format, no negotiation
19 },
20 });
21
22 if (response.status === 506) {
23 // Last resort - accept anything (no negotiation)
24 response = await fetch('/api/resource', {
25 headers: {
26 'Accept': '*/*',
27 },
28 });
29 }
30 }
31
32 return response.json();
33}
34
35// Avoid triggering negotiation loops
36async function fetchResourceSimple(url) {
37 // Use simple Accept header to avoid negotiation issues
38 const response = await fetch(url, {
39 headers: {
40 'Accept': 'application/json', // Single format
41 },
42 });
43
44 if (response.status === 506) {
45 throw new Error('Server configuration error: variant negotiation loop');
46 }
47
48 return response.json();
49}Express.js: Fix Content Negotiation Configuration
1// Server-side: Fix content negotiation to prevent 506
2const express = require('express');
3const app = express();
4
5// BAD: This causes 506 - variant tries to negotiate itself
6app.get('/api/resource', (req, res) => {
7 const acceptHeader = req.headers.accept;
8
9 // Don't create variants that negotiate themselves
10 // Variant resources should return content directly, not negotiate
11
12 // GOOD: Return content directly based on Accept header
13 if (acceptHeader.includes('application/json')) {
14 res.json({ data: 'content' });
15 } else if (acceptHeader.includes('application/xml')) {
16 res.set('Content-Type', 'application/xml');
17 res.send('<data>content</data>');
18 } else {
19 // Default to JSON
20 res.json({ data: 'content' });
21 }
22});
23
24// Prevent negotiation loops
25const preventNegotiationLoop = (req, res, next) => {
26 // Check if we're already in a negotiation context
27 if (req.headers['x-negotiation-depth']) {
28 const depth = parseInt(req.headers['x-negotiation-depth']);
29 if (depth > 1) {
30 return res.status(506).json({
31 error: 'Variant Also Negotiates',
32 message: 'Content negotiation loop detected',
33 });
34 }
35 }
36
37 // Add depth tracking
38 req.headers['x-negotiation-depth'] =
39 (parseInt(req.headers['x-negotiation-depth'] || '0') + 1).toString();
40
41 next();
42};
43
44// Apply to negotiation endpoints
45app.use('/api/variants', preventNegotiationLoop);Nginx: Fix Content Negotiation
1# Nginx: Configure content negotiation properly to prevent 506
2server {
3 listen 80;
4 server_name api.example.com;
5
6 # Enable content negotiation
7 location /api/resources/ {
8 # Don't create recursive negotiation
9 # Variants should be static files, not dynamic negotiation
10
11 # Serve JSON by default
12 try_files $uri.json $uri/index.json =404;
13
14 # Or proxy to backend (backend handles negotiation)
15 proxy_pass http://backend;
16 proxy_set_header Host $host;
17 proxy_set_header Accept $http_accept;
18
19 # Backend should not create variants that negotiate
20 }
21
22 # Avoid variant negotiation loops
23 # Don't configure variants that point to other variants
24}↗Related Errors
Provider Information
This error code is specific to HTTP services. For more information, refer to the official HTTP documentation.