HTTP
300 - Multiple Choices
Seeing a 300 Multiple Choices means the server found multiple representations of the resource and can't decide which one to return—different formats, languages, or versions are available. This client-side informational response (3xx) requires the client to choose. Most common when content negotiation offers multiple options, but also appears when resources exist in multiple formats, servers provide multiple versions, or Accept headers match several variants.
#Common Causes
- →Frontend: Accept header matches multiple content types. Multiple resource formats available. Content negotiation offers several options. No specific format preference.
- →Backend: Server has multiple representations of resource. Content negotiation returns multiple matches. Resource available in different formats/languages. Server can't choose default.
- →Infrastructure: CDN serves multiple variants. Load balancer routes to different formats. Reverse proxy offers multiple options.
✓Solutions
- 1Step 1: Diagnose - Check DevTools Network tab Response body—300 responses usually list available options. Review Link headers for variant URLs. Check Content-Location headers.
- 2Step 2: Diagnose - Server logs show which variants matched. Review content negotiation configuration. Check available resource formats. Examine Accept header matching.
- 3Step 3: Fix - Client-side: Specify preferred format in Accept header. Use more specific Accept values. Follow Link headers to choose variant. Implement content negotiation logic.
- 4Step 4: Fix - Server-side: Return 300 with Link headers listing variants. Provide Content-Location for each variant. Set default format if possible. Improve content negotiation.
- 5Step 5: Fix - Infrastructure: Configure CDN variant selection. Review load balancer content negotiation. Update reverse proxy variant handling.
</>Code Examples
Fetch API: Handle 300 Multiple Choices
1// Client-side: Handle 300 by choosing preferred format
2async function fetchResourceWithChoice(url) {
3 let response = await fetch(url);
4
5 if (response.status === 300) {
6 // Multiple choices available - parse options
7 const links = response.headers.get('Link');
8 const contentType = response.headers.get('Content-Type');
9
10 // Parse Link header for available variants
11 const variants = parseLinkHeader(links);
12 console.log('Available variants:', variants);
13
14 // Choose based on Accept header preference
15 response = await fetch(url, {
16 headers: {
17 'Accept': 'application/json', // Specify preferred format
18 },
19 });
20
21 // If still 300, choose first variant from Link header
22 if (response.status === 300 && variants.length > 0) {
23 const preferredVariant = variants.find(v => v.rel === 'alternate' && v.type === 'application/json')
24 || variants[0];
25 response = await fetch(preferredVariant.url);
26 }
27 }
28
29 return response.json();
30}
31
32// Parse Link header
33function parseLinkHeader(linkHeader) {
34 if (!linkHeader) return [];
35
36 const links = linkHeader.split(',');
37 return links.map(link => {
38 const parts = link.split(';');
39 const url = parts[0].trim().slice(1, -1); // Remove < >
40 const params = {};
41
42 parts.slice(1).forEach(param => {
43 const [key, value] = param.trim().split('=');
44 params[key] = value?.replace(/"/g, '');
45 });
46
47 return { url, ...params };
48 });
49}
50
51// Automatic format selection
52async function fetchWithAutoSelection(url, preferredFormat = 'application/json') {
53 const response = await fetch(url, {
54 headers: {
55 'Accept': preferredFormat,
56 },
57 });
58
59 if (response.status === 300) {
60 // Use more specific Accept header
61 return fetch(url, {
62 headers: {
63 'Accept': `${preferredFormat}, */*;q=0.1`,
64 },
65 });
66 }
67
68 return response.json();
69}Express.js: Return 300 with Variants
1// Server-side: Return 300 with multiple choices
2const express = require('express');
3const app = express();
4
5// Resource with multiple representations
6app.get('/api/resource', (req, res) => {
7 const acceptHeader = req.headers.accept || '*/*';
8
9 // Check if multiple formats match
10 const formats = ['application/json', 'application/xml', 'text/html'];
11 const matches = formats.filter(format =>
12 acceptHeader.includes(format) || acceptHeader === '*/*'
13 );
14
15 if (matches.length > 1) {
16 // Multiple choices - return 300 with Link headers
17 const links = formats.map(format => {
18 const url = `/api/resource.${format.split('/')[1]}`;
19 return `<${url}>; rel="alternate"; type="${format}"`;
20 }).join(', ');
21
22 return res.status(300)
23 .set('Link', links)
24 .set('Content-Type', 'text/html')
25 .send(`
26 <html>
27 <body>
28 <h1>Multiple Choices</h1>
29 <p>Available formats:</p>
30 <ul>
31 <li><a href="/api/resource.json">JSON</a></li>
32 <li><a href="/api/resource.xml">XML</a></li>
33 <li><a href="/api/resource.html">HTML</a></li>
34 </ul>
35 </body>
36 </html>
37 `);
38 }
39
40 // Single match - return that format
41 if (matches.includes('application/json')) {
42 res.json({ data: 'resource' });
43 } else if (matches.includes('application/xml')) {
44 res.set('Content-Type', 'application/xml');
45 res.send('<data>resource</data>');
46 } else {
47 res.send('<html><body>resource</body></html>');
48 }
49});
50
51// Variant endpoints
52app.get('/api/resource.json', (req, res) => {
53 res.json({ data: 'resource' });
54});
55
56app.get('/api/resource.xml', (req, res) => {
57 res.set('Content-Type', 'application/xml');
58 res.send('<data>resource</data>');
59});Nginx: Content Negotiation with Multiple Choices
1# Nginx: Handle multiple choices in content negotiation
2server {
3 listen 80;
4 server_name api.example.com;
5
6 location /api/resource {
7 # Enable content negotiation
8 index index.json index.xml index.html;
9
10 # If multiple formats exist, return 300
11 # Or let backend handle it
12 proxy_pass http://backend;
13 proxy_set_header Host $host;
14 proxy_set_header Accept $http_accept;
15 }
16
17 # Or serve static variants
18 location /api/resource.json {
19 default_type application/json;
20 return 200 '{"data":"resource"}';
21 }
22
23 location /api/resource.xml {
24 default_type application/xml;
25 return 200 '<data>resource</data>';
26 }
27}↗Related Errors
Provider Information
This error code is specific to HTTP services. For more information, refer to the official HTTP documentation.