Skip to content

HTTP status code · Redirection (3xx)

300 Multiple Choices

300 Multiple Choices means the resource has several representations, such as the same document in different formats or languages, and the server wants the client to choose. In practice it almost only comes from content negotiation setups like Apache MultiViews that cannot pick between equally good variants.

Facts about this status code
Class3xx, Redirection
Defined inRFC 9110 §15.4.1
Cacheable by defaultYes, heuristically cacheable
Safe to retryPick one of the listed alternatives, or follow Location if the server sent one
Relevant headers
  • Location: optional: the server's preferred choice, which clients may follow automatically
  • Link: one way to list the alternatives, with rel="alternate"

What 300 means

RFC 9110, section 15.4.1, describes 300 as reactive negotiation: instead of choosing a representation itself, the server lists the alternatives and lets the user or user agent follow the one it prefers. If the server does have a favorite, it should name it in the Location header, and a client may follow that automatically.

The spec never standardized a format for the list of alternatives, so browsers simply render the response body and leave the choice to the person reading it. That is why the code is rare: proactive negotiation, where the server reads Accept and Accept-Language and just picks, won almost everywhere. Unlike most 3xx codes, a 300 is heuristically cacheable.

When to use it

  • Only when the server genuinely cannot choose and a human choice is acceptable, for example a dataset offered as CSV, JSON and Parquet to a client that sent no useful Accept header.
  • Send a Location header with your preferred variant so clients that auto-follow still land somewhere sensible, plus a short HTML or JSON list of the alternatives in the body.

Common causes

If you run the server

  • Apache mod_negotiation with Options +MultiViews finds several files that match equally well, such as report.en.html and report.pt.html, and returns 300 with a list instead of choosing.

How to fix it

If you are visiting the site

  • Click the version you want in the list the page shows; the server is waiting for that choice.

If you run the server

  • Add ForceLanguagePriority Prefer Fallback with a LanguagePriority list so Apache serves one variant, or turn MultiViews off and link to explicit URLs.
  • For APIs, negotiate with Accept and return 200 with the chosen format, or 406 when none fits.

How to send 300

Express (Node.js)
app.get('/datasets/:name', (req, res) => {
  res.set('Location', '/datasets/sales.csv');
  res.status(300).json({ choices: ['/datasets/sales.csv', '/datasets/sales.json', '/datasets/sales.parquet'] });
});
Next.js App Router route handler
// app/datasets/[name]/route.ts
export async function GET() {
  return Response.json(
    { choices: ['/datasets/sales.csv', '/datasets/sales.json', '/datasets/sales.parquet'] },
    { status: 300, headers: { 'Location': '/datasets/sales.csv' } }
  );
}
Go net/http
mux.HandleFunc("GET /datasets/{name}", func(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Location", "/datasets/sales.csv")
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusMultipleChoices) // 300
	w.Write([]byte(`{"choices":["/datasets/sales.csv","/datasets/sales.json","/datasets/sales.parquet"]}`))
})
Python FastAPI
from fastapi import FastAPI
from fastapi.responses import JSONResponse

app = FastAPI()

@app.get("/datasets/{name}")
def get_dataset(name: str):
    return JSONResponse(status_code=300, content={"choices": ["/datasets/sales.csv", "/datasets/sales.json", "/datasets/sales.parquet"]}, headers={"Location": "/datasets/sales.csv"})

Commonly confused with

300 vs 406
406 Not Acceptable means none of the representations matches what the client asked for; 300 means several would do and the client should pick.
300 vs 302
302 points to exactly one other URL; 300 offers a menu of them.

Frequently asked questions

Do browsers follow a 300 Multiple Choices automatically?
Only when the response includes a Location header, and even then behavior varies by client. Without Location the browser renders the body as a page, so it has to contain clickable links to each alternative.
Why does Apache return 300 Multiple Choices?
MultiViews content negotiation found several files for the requested name that score the same against the request headers. ForceLanguagePriority Prefer makes Apache pick one using LanguagePriority instead of asking.
Should a REST API use 300 Multiple Choices?
Rarely. APIs usually negotiate with the Accept header and return 200 in the chosen format, or 406 when nothing fits. A 300 forces every client to implement a selection step that no standard describes.

Last reviewed by Arielton Oberek.