HTTP
406 - Not Acceptable
Getting a 406 Not Acceptable means the server can't produce a response in any format your Accept header requests—asking for application/xml when the server only serves JSON, or requesting a language/encoding the server doesn't support. This client-side error (4xx) happens when content negotiation fails. Most common when Accept headers request unsupported MIME types, but also appears when language preferences (Accept-Language) aren't available, character encodings (Accept-Encoding) are unsupported, or quality values (q=) prioritize unavailable formats.
#Common Causes
- →Frontend: Accept header requests unsupported format (application/xml when server only does JSON). Accept-Language requests unavailable language. Accept-Encoding requests unsupported compression. Quality values prioritize unavailable formats. Missing fallback options in Accept header.
- →Backend: Server only supports specific content types. Content negotiation middleware rejects Accept header. Language/encoding not configured. Server doesn't implement requested format.
- →Infrastructure: API gateway enforces content type restrictions. Load balancer modifies Accept headers. Reverse proxy doesn't support content negotiation. CDN restricts available formats.
✓Solutions
- 1Step 1: Diagnose - Check DevTools Network tab Request Headers—review Accept header values. Verify if requested format is supported. Check Accept-Language and Accept-Encoding headers. Review quality values.
- 2Step 2: Diagnose - Server logs show which Accept value was rejected. Review API documentation for supported formats. Check server content negotiation configuration. Verify infrastructure header handling.
- 3Step 3: Fix - Client-side: Add fallback options to Accept header (application/json, application/xml;q=0.9). Use wildcard as last resort (*/*). Remove unsupported format requests. Simplify Accept header.
- 4Step 4: Fix - Server-side: Support multiple content types (JSON, XML, etc.). Return 406 with Vary and Accept headers showing supported formats. Implement content negotiation properly. Add format detection.
- 5Step 5: Fix - Infrastructure: Configure API gateway to pass Accept headers. Review reverse proxy content negotiation. Update CDN format support. Ensure load balancer preserves headers.
</>Code Examples
Fetch API: Handle 406 with Accept Header Fallback
1// Client-side: Handle 406 by adjusting Accept header
2async function fetchWithContentNegotiation(url) {
3 // Try with preferred format first
4 let response = await fetch(url, {
5 headers: {
6 'Accept': 'application/json, application/xml;q=0.9, text/plain;q=0.8',
7 },
8 });
9
10 if (response.status === 406) {
11 // Check what formats server supports
12 const acceptHeader = response.headers.get('Accept');
13 console.warn(`Server doesn't support requested formats. Available: ${acceptHeader}`);
14
15 // Fallback to JSON only
16 response = await fetch(url, {
17 headers: {
18 'Accept': 'application/json',
19 },
20 });
21
22 if (response.status === 406) {
23 // Last resort - accept anything
24 response = await fetch(url, {
25 headers: {
26 'Accept': '*/*',
27 },
28 });
29 }
30 }
31
32 return response.json();
33}
34
35// Handle language negotiation
36async function fetchWithLanguage(url, preferredLanguage = 'en-US') {
37 const response = await fetch(url, {
38 headers: {
39 'Accept': 'application/json',
40 'Accept-Language': `${preferredLanguage}, en;q=0.9, *;q=0.8`,
41 },
42 });
43
44 if (response.status === 406) {
45 // Fallback to English
46 return fetch(url, {
47 headers: {
48 'Accept': 'application/json',
49 'Accept-Language': 'en',
50 },
51 }).then(r => r.json());
52 }
53
54 return response.json();
55}Express.js: Content Negotiation Middleware
1// Server-side: Implement content negotiation
2const express = require('express');
3const app = express();
4
5// Content negotiation middleware
6const contentNegotiation = (req, res, next) => {
7 const acceptHeader = req.headers.accept || '*/*';
8 const acceptedTypes = acceptHeader.split(',').map(type => {
9 const [mimeType, qValue] = type.trim().split(';q=');
10 return {
11 type: mimeType.trim(),
12 q: qValue ? parseFloat(qValue) : 1.0,
13 };
14 }).sort((a, b) => b.q - a.q);
15
16 // Check if server supports any requested format
17 const supportedTypes = ['application/json', 'application/xml', 'text/plain'];
18 const supported = acceptedTypes.find(accepted =>
19 supportedTypes.some(supported =>
20 accepted.type === supported || accepted.type === '*/*'
21 )
22 );
23
24 if (!supported && !acceptedTypes.some(a => a.type === '*/*')) {
25 return res.status(406)
26 .set('Vary', 'Accept')
27 .json({
28 error: 'Not Acceptable',
29 message: 'Server cannot produce a response in the requested format',
30 supported: supportedTypes,
31 requested: acceptedTypes.map(a => a.type),
32 });
33 }
34
35 // Store preferred format
36 req.preferredFormat = supported?.type === '*/*'
37 ? 'application/json'
38 : supported?.type || 'application/json';
39
40 next();
41};
42
43// Route with content negotiation
44app.get('/api/data', contentNegotiation, (req, res) => {
45 const data = { message: 'Hello World', timestamp: Date.now() };
46
47 if (req.preferredFormat === 'application/xml') {
48 res.set('Content-Type', 'application/xml');
49 res.send(`<?xml version="1.0"?><data><message>${data.message}</message></data>`);
50 } else {
51 res.json(data);
52 }
53});Nginx: Pass Accept Headers
1# Nginx: Ensure Accept headers reach backend
2server {
3 listen 80;
4 server_name api.example.com;
5
6 location /api/ {
7 proxy_pass http://backend;
8 proxy_set_header Host $host;
9 proxy_set_header X-Real-IP $remote_addr;
10
11 # Pass Accept headers to backend
12 proxy_set_header Accept $http_accept;
13 proxy_set_header Accept-Language $http_accept_language;
14 proxy_set_header Accept-Encoding $http_accept_encoding;
15
16 # Backend handles content negotiation
17 }
18}↗Related Errors
Provider Information
This error code is specific to HTTP services. For more information, refer to the official HTTP documentation.