Multiple Choices
ActiveHTTP 300 Multiple Choices indicates the target resource has more than one representation, each with its own identifier. Defined in RFC 9110 §15.4.1. The server provides a list of choices so the user agent can select a preferred one. If the server has a preferred choice, it SHOULD include a Location header.
Description
The 300 Multiple Choices status code indicates that the target resource has more than one representation, each with its own more specific identifier. The server is providing the available choices so the user or user agent can select the preferred one by redirecting its request to one or more of those identifiers.
If the server has a preferred choice, the server SHOULD generate a Location header field containing a preferred choice's URI reference. The user agent MAY use the Location field value for automatic redirection. The response body SHOULD contain a list of representation metadata and URI references from which the user or user agent can choose the most appropriate one.
300 is the theoretical success case of content negotiation. In practice, it's almost never seen in the wild because servers handle content negotiation transparently using Accept, Accept-Language, and Accept-Encoding headers — the client states preferences, the server picks the best match, and responds directly with 200. The 300 response exists for cases where the server cannot or will not choose on the client's behalf.
The distinction from 406 Not Acceptable is critical: 406 means the server cannot produce ANY acceptable representation. 300 means the server CAN produce multiple acceptable representations and is asking the client to pick. One is failure (406), the other is optionality (300).
Cacheable only if explicit caching headers (Cache-Control, Expires) are present in the response. Without those headers, intermediaries and clients MUST NOT cache the 300 response, since the available choices may change over time.
Examples
GET /api/reports/annual-2024 HTTP/1.1
Host: docs.example.com
Accept: application/pdf, text/html, application/epub+zipHTTP/1.1 300 Multiple Choices
Content-Type: application/json
Location: /api/reports/annual-2024.pdf
{"choices": [{"href": "/api/reports/annual-2024.pdf", "type": "application/pdf", "title": "PDF (2.4 MB)"}, {"href": "/api/reports/annual-2024.html", "type": "text/html", "title": "HTML (interactive)"}, {"href": "/api/reports/annual-2024.epub", "type": "application/epub+zip", "title": "EPUB (1.1 MB)"}]}GET /legal/terms HTTP/1.1
Host: example.com
Accept-Language: *HTTP/1.1 300 Multiple Choices
Content-Type: text/html
Location: /legal/terms/en
Vary: Accept-Language
<html><body>
<h1>Multiple Choices</h1>
<ul>
<li><a href="/legal/terms/en">English</a></li>
<li><a href="/legal/terms/es">Español</a></li>
<li><a href="/legal/terms/de">Deutsch</a></li>
<li><a href="/legal/terms/ja">日本語</a></li>
</ul>
</body></html>GET /api/users/42 HTTP/1.1
Host: api.example.com
Accept: application/jsonHTTP/1.1 300 Multiple Choices
Content-Type: application/json
Location: /api/v3/users/42
{"message": "Multiple API versions available for this resource.", "choices": [{"href": "/api/v3/users/42", "version": "v3", "status": "current"}, {"href": "/api/v2/users/42", "version": "v2", "status": "deprecated"}, {"href": "/api/v1/users/42", "version": "v1", "status": "legacy"}]}Edge Cases
- •300 is cacheable ONLY if explicit caching headers are present. Without Cache-Control or Expires, the response MUST NOT be cached — the available representations may change at any time.
- •If a Location header is included, user agents MAY automatically redirect to it without presenting the choice list to the user. Browsers typically follow Location automatically, making 300 behave like 302 in practice.
- •The response body format is not standardized. It can be HTML with links, JSON with an array of choices, or any other format — as long as the user agent can parse it to extract alternatives.
- •300 is NOT appropriate when the server can determine the best representation from the request's Accept headers. Use transparent content negotiation (200 with Vary) instead. 300 is for when the server genuinely cannot choose.
- •Circular references: if choice A points back to the original URI which returns 300 again, the client enters a redirect loop. Servers MUST ensure each choice URI resolves to a concrete representation.
- •Some proxies and CDNs strip or ignore 300 responses, converting them to 200 with the first available representation. Test proxy behavior before relying on 300 in production architectures.
When You'll See This
- →Document available in multiple formats: PDF, EPUB, HTML, DOCX — server cannot determine preference
- →Legal or compliance pages available in multiple languages with no Accept-Language header sent
- →API endpoint serving multiple versions of the same resource without version in URL path
- →Media content available at different quality levels (4K, 1080p, 720p) when client capabilities are unknown
- →Academic paper available in multiple citation formats (BibTeX, RIS, EndNote)
- →Software download page offering binaries for multiple platforms (macOS, Windows, Linux)
- →REST resource with multiple serialization formats (JSON, XML, MessagePack, CBOR) and no Accept header
Implementation References
| Language | Constant |
|---|---|
| Go | http.StatusMultipleChoices |
| Rust | http::StatusCode::MULTIPLE_CHOICES |
| Python | http.HTTPStatus.MULTIPLE_CHOICES |
| Node.js | http.STATUS_CODES[300] |
| .NET | HttpStatusCode.MultipleChoices |
| Java | HttpURLConnection.HTTP_MULT_CHOICE |
| PHP | Response::HTTP_MULTIPLE_CHOICES (Symfony) |
| Ruby | :multiple_choices (Rack) |
History
Introduced in HTTP/1.1 (RFC 2068, 1997) as part of the content negotiation framework. The original vision was that user agents would present a choice UI — imagine a browser dialog asking 'This document is available in PDF, HTML, and EPUB. Which do you prefer?' This never materialized in mainstream browsers. Instead, the Accept/Accept-Language/Accept-Encoding header system made server-driven negotiation the default. RFC 2616 (1999) refined the semantics. RFC 7231 (2014) further clarified that 300 is for cases where the server does not have a preferred representation or cannot determine the user's preference. RFC 9110 (2022) consolidated the definition without behavioral changes. Despite being defined for 27+ years, 300 remains one of the rarest HTTP status codes encountered in production.
Related Status Codes
Related Headers
FAQ
Why is HTTP 300 almost never seen in practice?
Server-driven content negotiation via Accept headers made 300 unnecessary for most use cases. When a client sends Accept: text/html, the server picks HTML and responds with 200. The 300 response was designed for cases where the server cannot or will not choose — but browsers never built a good UI for presenting choices to users, so servers learned to just pick the most common format. Additionally, proxies and CDNs often don't handle 300 gracefully, further discouraging its use. The code exists in the spec but the ecosystem evolved around transparent negotiation instead.
What is the difference between 300 Multiple Choices and 406 Not Acceptable?
They are opposite outcomes of content negotiation. 300 means success with options — the server HAS multiple valid representations and is asking the client to choose. 406 means failure — the server cannot produce ANY representation matching the client's Accept headers. Think of it as: 300 is 'I have too many options for you, pick one' while 406 is 'I have nothing that matches what you asked for.' In practice, most servers skip 300 entirely and either serve the best match (200) or reject with 406.
How should a client handle a 300 Multiple Choices response?
If a Location header is present, the client MAY automatically follow it as a redirect — most browsers do this. If no Location header exists, the client should parse the response body to extract the list of available representations. For API clients, this means reading the JSON body and selecting the appropriate href based on content type, language, or version preferences. Programmatic clients should implement selection logic rather than blindly following Location, since the Location value is the server's preference — not necessarily the client's optimal choice.