405
How to fix HTTP 405 Method Not Allowed
The path exists and the server recognises the verb — it just does not accept that verb here, and it is required to hand you the list of verbs it does accept.
Why you are seeing 405, and what to do about it
The same three digits are three different problems depending on which side of the request you are on. Read the block that describes you.
Front-end developer
Why you are seeing it
The most common 405 in a browser is one you never wrote. A cross-origin request carrying a JSON content type or a custom header is preflighted, so the browser sends an `OPTIONS` request first, and a server whose router only registers GET and POST answers that preflight with 405. What you then see in the console is a CORS error, because the preflight did not succeed — and the CORS message hides the 405 underneath it, so people spend hours on `Access-Control-Allow-Origin` for a problem that is a missing route. The second shape is a POST that arrives as a GET. RFC 9110 §15.4.2 records that user agents have historically rewritten POST to GET when following a 301 or 302, so a form posted to an `http://` URL that redirects to `https://`, or to a path that redirects to add a trailing slash, reaches the server as the wrong verb entirely.
What to do
Read the method of the failed request in the network panel before anything else, because it is frequently not the method you called. If it says OPTIONS, the work is server-side — answer preflights with the CORS headers and a 204 — and no change to your `fetch` will help. Then read the `allow` header on the 405 itself: §15.5.6 makes it mandatory, and it is a direct statement of which verbs that path takes, which usually ends the investigation on the spot. If a redirect is in the chain, send the request to the final URL instead, and prefer servers that use 307 or 308 for anything that might be a POST, since those are the two redirects that preserve the method. Finally, purge the edge after you fix it, because a cached 405 is a real possibility here.
Back-end developer
Why you are seeing it
The router matched the path and not the verb — or something rewrote one of them on the way in. Frameworks disagree about how to say this: some answer 405 with a correct `Allow` header, some answer 404 for an unmatched verb, so the identical bug looks like two different problems in two of your own services. Static file serving is its own case: nginx's static module serves only GET and HEAD, so a POST aimed at a path that resolves to a file on disk comes back as `405 Not Allowed` from nginx rather than from your application, which is why the request never appears in your application log. Path rewriting supplies the rest: a rewrite that adds or strips a trailing slash can move a POST onto a route registered only for GET, and a proxy that redirects `/api/users` to `/api/users/` gives the client the chance to downgrade the method on the way.
What to do
Dump the route table and compare method and path as a pair, not as two separate facts — every framework has a command for this and it is faster than reading the router. Confirm your 405s actually carry `Allow`, since it is a MUST and it is the single most useful thing the response can say; a framework that omits it is turning a one-minute client-side fix into a support conversation. Check specifically whether you are 405ing `HEAD` or `OPTIONS` by accident: §9.1 requires GET and HEAD on general-purpose servers, and OPTIONS is what every browser preflight uses, so those two are the ones most likely to break something you did not test. If the 405 never reaches your application log, look at the static file handler and the rewrite rules instead. And purge the CDN afterwards, because §15.1 makes this response cacheable by heuristic.
End user
Why you are seeing it
You are very unlikely to have caused this one. It usually appears after you submitted a form — instead of a confirmation you get a short error page — and it means the site's form is pointed at an address that does not accept submissions. It can also show up after following an old bookmark or a link that switched between the `www.` and plain versions of a site, because the redirect on the way can turn your submission into an ordinary page request. Nothing is wrong with your browser, your device or the data you entered.
What to do
Do not reload the error page — a reload sends the same rejected submission again and it will fail identically, and some browsers will also warn you about resubmitting. Go back to the form, start from the site's home page over `https://` so nothing is redirected on the way, and submit once. If the site has both a `www.` and a non-`www.` address, use whichever one the site's own links use. If it still fails, this is a wiring mistake on the site's side, and the useful thing to report is the exact page you were on and which button you pressed.
Reproduce 405 with curl
Run this against the URL that failed. It prints the status without the error page, so you can see what the server said rather than what the browser rendered.
curl -sS -X POST -o /dev/null -D - -w '\n%{http_code}\n' https://example.com/`-X POST` replaces the method curl would otherwise use, `-o /dev/null` discards the error page, and `-D -` dumps the response headers, which is where the answer is. The header to find is `allow`: §15.5.6 makes it mandatory on a 405 and it lists the methods that path really accepts, so a single run tells you whether your call was wrong or your route is. Read its absence as a finding too — a 405 with no `Allow` is a server that is not answering to spec, and an `Allow` present but empty legitimately means the resource accepts nothing at all. Two variants are worth the extra seconds. `curl -I` sends a HEAD rather than a GET, so a 405 you get from `-I` may be about HEAD alone and not about the verb you actually care about, which §9.1 makes a server defect where GET works. And to reproduce a browser preflight rather than guess at it, run `curl -sS -D - -o /dev/null -X OPTIONS -H 'origin: https://app.example.com' -H 'access-control-request-method: POST' https://example.com/api/` — a 405 there is the real cause behind a CORS message that never mentions it.
What 405 actually means
RFC 9110 §15.5.6 defines 405 as the method in the request line being known by the origin server but not supported by the target resource, and it makes the useful half mandatory: the origin server MUST generate an `Allow` header field in a 405 response listing the target resource's currently supported methods. `Allow` is defined in §10.2.1, and it has one detail worth knowing before you misread it — an empty `Allow` field value is legal and means the resource supports no methods at all, which is not the same as the header being absent. Two neighbouring codes bound the meaning. §15.6.2 reserves 501 (Not Implemented) for a method the server does not support for any resource, so 405 is the narrower statement: the server knows this verb, just not here. And §9.1 requires that all general-purpose servers support GET and HEAD, which makes a 405 in response to a HEAD on a resource whose GET works a defect rather than a policy — worth remembering because `curl -I` sends HEAD, so the tool you reach for first can manufacture the very code you are investigating. The last property is the one that outlives the deploy: 405 is one of the status codes RFC 9110 §15.1 lists as heuristically cacheable, alongside 404, 410 and 501, which means a cache or CDN may store one with no explicit `Cache-Control` at all. A route that answered 405 for ten minutes during a bad rollout can therefore keep answering 405 from the edge after the rollout is fixed, until the stored response expires or somebody purges it — the same trap 404 has, and for the same reason.
Codes 405 gets mistaken for
| Confused with | How to tell them apart |
|---|---|
501 | 501 (Not Implemented, §15.6.2) means the server does not support the method for any resource; 405 means it supports the method but not on this one. The practical difference is where you go next: a 501 for `PATCH` from a proxy or an old server is a capability gap you route around, while a 405 for `PATCH` from your own application is a route you did not register. Both are heuristically cacheable under §15.1, so both can outlive their cause. |
| 404 | A router that answers 404 for an unmatched verb hides the more useful half of the answer, and §15.5.6 is the reason the distinction matters: 405 comes with `Allow`, and 404 comes with nothing. The test takes one command — if a path returns 404 for POST and 200 for GET, it is a 405 wearing the wrong number, and you should be looking at the method rather than at the path. |
| 301 | The 405 you are looking at may be an artefact of a redirect rather than of your call. §15.4.2 records that user agents have historically rewritten POST to GET when following 301, and the same is true in practice of 302, so a POST that crosses an `http://` to `https://` or a trailing-slash redirect can arrive as a GET on a route that only accepts POST. 307 and 308 are the redirects that preserve the method, which is why an API should use those. |
CORS preflight | A cross-origin request with a JSON body or a custom header is preceded by an `OPTIONS` request the browser generates itself, and a server without an OPTIONS route answers it with 405. The browser then reports a CORS failure, because the preflight did not succeed — so the message names the wrong problem, and the 405 sitting in the network panel one row above the failed request is the real one. |
Allow | §10.2.1 defines `Allow` as the list of methods supported by the target resource, and §15.5.6 makes sending it mandatory on a 405 — so its absence is a server bug rather than a hint. Read an empty value carefully: an empty `Allow` field value is a legal way to say the resource supports no methods at all, which is a different statement from the header not being there. |
- Reason phrase
- Method Not Allowed
- Class
- 4xx client error
- Defined by
- RFC 9110
- Standard
- IETF standard
Tools on this site
All of these run in your browser — nothing is uploaded.
- PCAP Viewer — open a capture and read the request line that actually reached the server, when a redirect or a rewrite turned your POST into something else
- Port Number Reference — confirm which service is listening where, when a submission redirected to another port lands on a server that never had your route
Related status codes
Codes people usually end up reading in the same session as 405.