ByteScope

405

How to fix HTTP 405 Method Not Allowed

4xx client errorIETF standardRFC 9110

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.

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
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 withHow to tell them apart
501501 (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.
404A 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.
301The 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 preflightA 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.

Related status codes

Codes people usually end up reading in the same session as 405.

Frequently asked questions

How do I find out which server produced this status code?

Read the response headers rather than the page. curl -sS -o /dev/null -D - https://example.com/path prints them without the body, and server, via and cf-ray between them name the layer that answered. A cf-ray value means Cloudflare handled the response and is the id their support will ask for. To take the edge out of the picture entirely, repeat the request with --resolve example.com:443:203.0.113.10, which connects to the origin address you name while still sending the original host name and SNI — if the answer changes, the edge and the origin disagree.

Does the reason phrase after the number matter?

No, and you should never branch on it. RFC 9112 tells clients to ignore the reason phrase, servers are free to change it, and HTTP/2 and HTTP/3 do not carry one at all — so 404 Not Found over HTTP/1.1 arrives as a bare 404 over HTTP/2. The phrases on this site are the registered ones because they are what people search for and what appears in an HTTP/1.1 log, not because any software depends on them.

Should I retry a request that failed with this code?

Retry 5xx and 429; do not retry 4xx, because nothing about the request will be different next time. If the response carries Retry-After, honour it — RFC 9110 defines it for exactly this, and it may be either a number of seconds or a date. Otherwise use exponential backoff with jitter and a hard cap, and only for idempotent methods: a retried POST can charge a card twice. A retry storm against a server that is already failing is how a brief incident becomes a long one.

Can I make my server return a different status code?

Yes, and the only rule that matters is that the code has to be true. Anything that reads your responses automatically — search engines, monitoring, caches, client retry logic — makes decisions from the number and never from the page. Serving an error page with 200 hides the failure from your own alerting; serving 200 for a missing page gets the error indexed as content; returning 500 for a request that was simply malformed sends whoever is on call to the wrong half of the stack.

Still stuck on 405? browse every status code in the reference — or go back up to the block written for your side of the stack.