Migrate to RunxBuild and earn up to $50 in hosting credit on your first deposit.

Calculate your savings
unxBuild
Back to Blog Troubleshooting

405 Method Not Allowed: What the Server Is Telling You, and the Six Places It Comes From

Sean

Platform Writer

Sep 13, 2026
8 min read

A 405 Method Not Allowed means the server recognised the URL but refuses the HTTP method you used on it. The resource exists; POST, PUT, DELETE or whatever you sent is not something it accepts there. The response is required to carry an Allow header listing the methods that would work. That header is the diagnosis: read it first, and the rest of this post is the list of layers that generate a 405 and how to tell which one you are looking at.

405 Method Not Allowed: What the Server Is Telling You, and the Six Places It Comes From

The reference pages define the status and stop. The troubleshooting pages list causes without saying how to tell them apart. What makes a 405 annoying in practice is that six different layers can produce one, from the framework router to a static host that has no idea what POST means, and they all look the same in the browser. So this is organised by layer, outermost first, with the tell for each.

Table of contents

Read the Allow header before anything else

The spec says a 405 must include an Allow header naming the methods the resource supports. Most frameworks and web servers honour that. So the first move is not to read the docs but to read the response:

curl -i -X POST https://example.com/api/items
# HTTP/1.1 405 Method Not Allowed
# Allow: GET, HEAD, OPTIONS

That tells you immediately whether the route is registered for the method you expected. If Allow lists only GET and you meant to POST, the route is missing or misregistered. If Allow lists POST and you still get 405, the request never reached the code that would accept it, and something in front of it answered instead. Those are two completely different investigations, and the header sorts them in one line.

If there is no Allow header at all, that is itself a clue: static hosts, CDNs and some proxies emit a bare 405 without one, which points you at the outer layers straight away.

404 versus 405, and why the difference matters

A 404 says the resource does not exist. A 405 says it exists, but not for that verb. That distinction is why a form that GETs fine and 405s on submit is not a broken URL: the URL is right, the handler for POST is missing. A 404 investigation starts at the path and the rewrites; a 405 investigation starts at the method table.

The related code people confuse it with is 403, which is a permission refusal: the method is fine, you are not. And 501 Not Implemented means the server does not know the method at all, anywhere, which is rare and usually means someone typed a verb that does not exist.

The six layers that produce a 405

Outermost first, because the outer layers answer before the inner ones get a chance.

  1. A static host. Static file hosting serves GET and HEAD. POST to a page on a static site returns 405, because there is no process to receive a body. This is the most common one for people who just deployed a form to a static site and are surprised. The fix is not on the host: the form needs a backend, a form service, or a function.
  2. A CDN or proxy. Some cache and edge configurations allow only a listed set of methods, and reject the rest before the origin sees them. The tell is a 405 with no Allow header and a response header naming the edge.
  3. The web server. Nginx returns 405 when a POST hits a location that serves static files, and Apache does the same when a Limit directive excludes the method. Look for the server header and the location block.
  4. The framework router. A route registered for GET only, a decorator listing methods that omits the one you sent, a resource route generated without the action. Allow will be accurate here and will show you what is registered.
  5. A redirect that changed the verb. A 301 or 302 turns a POST into a GET in most clients. If the form posts to /submit and the server redirects to /submit/ with a trailing slash, the second request is a GET, and now the GET-only handler on the other side complains, or the POST-only one does. Use 307 or 308 to preserve the method, or post to the canonical path.
  6. A CORS preflight. Browsers send OPTIONS before a cross-origin POST with custom headers. If nothing handles OPTIONS, the preflight gets a 405 and the browser reports a CORS failure, and the POST never happens. The 405 is in the network tab, not the console.

Work down the list with curl. Send the exact request the browser sent, with -i, and look at Allow, Server, and any edge headers. The layer that answered usually signs its work.

Fixes, by layer

  • Static host: give the form somewhere to post. A backend service, or a form endpoint on another host. Redirect-based tricks do not help because the redirect changes the method.
  • CDN or proxy: allow the method in the edge configuration, or route the API path around the cache entirely. API paths rarely benefit from edge caching anyway.
  • Nginx: make sure the location that receives the POST proxies to the app rather than serving a file. A try_files that falls through to a static file will 405 on POST. Send the request to the upstream and let the app decide.
  • Framework: register the route for the method. In Express that is app.post instead of app.get; in Flask it is methods=[POST] on the decorator; in Rails it is the resource action. The Allow header will confirm the fix.
  • Redirects: replace 301 and 302 with 307 or 308 where a POST may be redirected, and fix the trailing slash so the form posts to the final path in the first place.
  • CORS: handle OPTIONS explicitly and return the Access-Control-Allow-Methods header. Most frameworks have middleware; the React CORS on Vercel post covers the shape.

Why a working endpoint suddenly returns 405

Endpoints that worked yesterday and 405 today have usually been moved behind something new. A CDN was switched on. A static export replaced a server render. A framework upgrade changed how methods are declared. A trailing-slash redirect was added for SEO. The code did not change; the path to the code did.

The fastest way to prove that is to bypass the outer layer: hit the origin directly, or run the app locally, and send the same request. If it works there, the 405 is in the layer you bypassed. Deploy logs help too: on a platform that keeps deploy history and runtime logs together, the deploy that introduced the change is a diff away, and rolling back is a click rather than an archaeology project. Services on RunxBuild keep both, and a Node, Python or Go service can be rolled back to the previous deploy while you read the log.

A checklist for the next one

  1. curl -i with the exact method and path. Read Allow.
  2. Note which layer signed the response: framework, web server, edge.
  3. Check for a redirect in the chain with curl -iL and look for a 30x before the 405.
  4. If it is a browser cross-origin call, check the OPTIONS request in the network tab.
  5. If the route is on a static site, stop and add a backend.
  6. Fix at the layer that answered, then re-run the curl and confirm Allow now includes the method.

How this fits the rest of the stack

A 405 is one of the more honest errors: the server is telling you exactly what it would accept. The slow part is finding which layer said it. If the answer is that the form or the API needs a process behind it rather than a static file, the RunxBuild hosting calculator shows what adding a small backend service beside the static site costs, as separate line items, before you commit to it. Read the header, find the layer, fix it there.

Useful related references:

FAQ

What does 405 Method Not Allowed mean?

The server recognised the URL but does not accept the HTTP method you used on it. The resource exists; POST, PUT or DELETE is not supported there. The response should include an Allow header listing the methods that are supported, and that header is the first thing to read.

What is the difference between 404 and 405?

A 404 means the resource was not found at that path. A 405 means it was found but the method is wrong for it. A form that loads with GET and fails on submit is a 405 problem: the URL is correct and the POST handler is missing or blocked, not the page.

How do I fix a 405 error?

Send the request with curl -i and read the Allow header. If the method is missing from Allow, register the route for it in the framework. If it is present and you still get 405, something in front of the app answered: a static host, a CDN, the web server, or a redirect that converted the POST into a GET. Fix at the layer that responded.

Why do I get 405 when submitting a form on a static site?

Static hosting serves GET and HEAD only; there is no process to receive a POST body. The form needs a backend service or a form endpoint to post to. Redirecting the form elsewhere does not help, because a 301 or 302 redirect turns the POST into a GET.

Can a firewall or CDN cause a 405?

Yes. Edge and proxy configurations that allow only a listed set of methods reject the rest before the origin sees them. The tell is a 405 without an Allow header and response headers naming the edge. Allow the method for the API path or route that path around the cache.

#405 method not allowed#http 405#405 error#allow header#method not allowed fix