< HTTP/1.1 405 Method Not Allowed405 Method Not Allowed
405 Method Not Allowed means the URL exists but not for that method. Read the Allow header, then fix redirects turning POST into GET, static hosting and WAFs.
- Cacheable
- Yes, by default
- Retry?
- No: use a method listed in Allow
- Usually sent by
- Origin app or web server
- Spec
- RFC 9110 §15.5.6
On this page
TL;DR: 405 Method Not Allowed means the URL exists but does not accept the HTTP method you used, and the response must list the accepted methods in an
Allowheader. The usual real-world causes are a form or fetch using the wrong verb, a redirect that turned POST into GET, static hosting that only serves GET, and a proxy or CORS layer blocking PUT/DELETE.
RFC 9110 section 15.5.6: the method “is known by the origin server but not supported by the target resource”, and the server “MUST generate an Allow header field”. Compare 501, which means the server does not recognize the method at all, and 404, where the path itself is unknown.
HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
{"error":"method_not_allowed","allowed":["GET","HEAD","OPTIONS"]}
Who sent it?
| Evidence | Layer |
|---|---|
Allow: header lists methods and body comes from your framework (Method Not Allowed, Flask: The method is not allowed for the requested URL.) | Application route does not define that method |
nginx page 405 Not Allowed | nginx serving a static file (nginx static handling accepts only GET/HEAD, and POST to a static file returns 405) |
405 Method Not Allowed with Server: AmazonS3 | S3 website endpoint or bucket policy blocks the verb |
Server: cloudflare, CF-Ray | Cloudflare Pages/Workers or a WAF rule restricting methods |
IIS: HTTP Error 405.0 - Method Not Allowed or 405.0 ... The page you are looking for cannot be displayed because an invalid method (HTTP verb) is being used | IIS; frequently WebDAV module intercepting PUT/DELETE |
Spring: Request method 'POST' is not supported (HttpRequestMethodNotSupportedException) | Spring MVC mapping |
Django: Method Not Allowed (POST): /path/ in the server log | View class lacks post() |
Fix it, most common first
- Read the
Allowheader and use one of those methods:curl -si -X POST URL | grep -i '^allow', or ask withcurl -si -X OPTIONS URL. - A redirect changed your method. 301 and 302 make most clients re-issue POST as GET, and the target (say a GET-only page) answers 405. Typical triggers:
httptohttpsredirect,wwwto apex, trailing slash redirect. Call the final URL directly, or have the server use 307/308, which preserve the method. - Static hosting. POSTing a form to a page on GitHub Pages, S3 static hosting, Netlify without a function, or nginx
try_filesserving a file returns 405. Point the form to a real endpoint. - A framework route only handles some verbs. Add the handler. Next.js App Router needs an exported function named exactly
POST,PUTand so on inroute.ts; Express needsapp.post(...), and aGET-onlyapp.getyieldsCannot POST /path(404 from Express, not 405). - Proxy or WAF restrictions.
limit_except GET { deny all; }in nginx returns 403, not 405; but ModSecurity and CDN rules often return 405 for PUT, DELETE and PATCH. Allow the verbs for that path. - CORS preflight. An
OPTIONSrequest that your server answers with 405 breaks cross-origin PUT/DELETE/JSON POST. HandleOPTIONSand returnAccess-Control-Allow-Methods(see CORS preflight debugging). - HTML forms only do GET and POST.
<form method="put">is treated as GET. Usefetch, or a hidden_methodoverride your framework understands. - HEAD or OPTIONS rejected. Monitoring tools and crawlers send HEAD; a handler that omits it returns 405 and trips health checks. Most servers should accept HEAD wherever GET is accepted (RFC 9110 section 9.1).
Fix by stack
nginx
# POST to a location that serves static files => 405. Route it to the app instead.
location /api/ {
proxy_pass http://127.0.0.1:3000;
}
# Optional workaround for legacy POST-to-static
error_page 405 =200 $uri;
Apache
# Restrict verbs: denied methods get 403, not 405, unless you return 405 yourself
<LimitExcept GET POST OPTIONS>
Require all denied
</LimitExcept>
Express / Node.js
app.route('/api/items')
.get(listItems)
.post(createItem)
.all((req, res) => {
res.set('Allow', 'GET, POST, OPTIONS').status(405).json({ error: 'method_not_allowed' })
})
Next.js, Flask, Django
// app/api/items/route.ts : Next.js App Router
export async function GET() { return Response.json([]) }
export async function POST(req: Request) { return Response.json(await req.json(), { status: 201 }) }
// Any other method gets 405 with an automatic Allow header.
Flask returns 405 with an Allow header automatically when methods=[...] does not include the verb. Django class-based views return HttpResponseNotAllowed using http_method_not_allowed; DRF returns {"detail":"Method \"DELETE\" not allowed."}.
Reproduce and verify
curl -si -X DELETE https://api.example.com/items | sed -n '1p;/^[Aa]llow/p'
curl -si -X OPTIONS https://api.example.com/items | grep -i '^allow'
curl -sv -L -d 'a=1' http://example.com/form 2>&1 | grep -E '^> (POST|GET)'
The last command shows whether the second request in a redirect chain is still POST. Plain curl -L -d switches to GET after 301/302 unless you pass --post301/--post302, which is also what browsers do.
Related
405 lives next to 404, 501, and 400. Method semantics: GET, POST, PUT, DELETE, OPTIONS. Try a bad verb in the request builder.
Frequently asked questions
What does 405 Method Not Allowed mean?
The target resource exists and the method is recognized, but the resource does not support that method (RFC 9110 section 15.5.6). The response must carry an Allow header listing the supported methods.
Why do I get 405 when POSTing to a static page or form?
Static hosts such as S3 website hosting, GitHub Pages and nginx serving files only accept GET and HEAD, so a POST gets 405. Send the form to a real endpoint such as a server route or serverless function.
Why does my POST turn into a GET and return 405 after a redirect?
Browsers and curl change POST to GET after 301 and 302 responses, so the second request hits a GET-only URL. Call the final URL directly, or redirect with 307 or 308, which preserve the method.
What is the difference between 405 and 501?
405 means the server knows the method but the resource does not support it, and requires an Allow header. 501 means the server does not recognize or implement the method at all.
Why does an OPTIONS request return 405 in my CORS setup?
The server has no handler for the preflight OPTIONS request, so cross-origin PUT, DELETE and JSON POST requests fail in the browser. Add an OPTIONS handler returning Access-Control-Allow-Methods and Access-Control-Allow-Headers.
Sources
Related
400 Bad Request
400 Bad Request means the server could not parse your request. Find which layer sent it, fix bad JSON and oversized cookies or headers, and reproduce with curl.
406 Not Acceptable
The server cannot produce a response matching the client's Accept headers. Learn about content negotiation and how to handle format mismatches.
408 Request Timeout
408 Request Timeout means the server gave up waiting for the client to finish sending. Tune nginx, Apache, Node and ALB timeouts and tell it apart from 504.
409 Conflict
409 Conflict means the request clashes with the resource's current state: duplicates, stale versions, locks. Use ETags and If-Match, and handle retries.