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

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.

406 - Not Acceptable | HTTP Error Reference | Error Code Reference