,{"@context":"https://schema.org","@type":"FAQPage","mainEntity":[{"@type":"Question","name":"Why does my browser show 405 on form submit?","acceptedAnswer":{"@type":"Answer","text":"The form is POSTing to a URL configured for GET only. Check the form action URL and ensure the server route accepts POST. GET and POST routes are registered separately in most frameworks."}},{"@type":"Question","name":"Can 405 be returned for HEAD requests?","acceptedAnswer":{"@type":"Answer","text":"Technically, but RFC 9110 states any resource supporting GET must also support HEAD. Returning 405 for HEAD on a GET-enabled endpoint violates the spec. Most frameworks handle HEAD automatically."}}]}

HTTP 405 Method Not Allowed

Quick reference

Code405
NameMethod Not Allowed
Category4xx Client Error
SpecRFC 9110 §15.5.6
Required headerAllow: listing supported methods

What 405 means

HTTP 405 Method Not Allowed means the server understands the HTTP method in the request (GET, POST, PUT, DELETE, PATCH, etc.) but the target resource does not support that method. RFC 9110 §15.5.6 requires the server to include an Allow: response header listing the methods the resource does support. A 405 without an Allow: header is a violation of the specification.

The key difference between 405 and 501 Not Implemented: 405 means the server knows the method and the resource does not support it. 501 means the server does not know the method at all. 405 is a per-resource restriction; 501 is a server-wide capability gap.

405 responses are cacheable by default (RFC 9110 lists it among default-cacheable codes). Caches may store a 405 and replay it for the same method on the same URL. Include Cache-Control: no-store if the allowed methods are subject to change.

The Allow header

Every 405 response must include an Allow: header. This tells the client what methods it can use instead:

# 405 response for a read-only endpoint: HTTP/1.1 405 Method Not Allowed Allow: GET, HEAD, OPTIONS Content-Type: application/json {"error": "method_not_allowed", "allowed": ["GET", "HEAD", "OPTIONS"]} # 405 response for a create-only endpoint: HTTP/1.1 405 Method Not Allowed Allow: POST, OPTIONS Content-Type: application/json {"error": "method_not_allowed", "allowed": ["POST", "OPTIONS"]}

The Allow header is also returned with 204 No Content for OPTIONS preflight requests — this is how CORS works. Always keep Allow accurate and complete.

Common causes

Wrong HTTP method for the endpoint. A client sends DELETE to a resource that only supports GET and POST. The fix is on the client side: use the correct method. Check the API documentation for the correct method for each operation.

Calling a list endpoint with an ID method. REST APIs often have two URL patterns: GET /users (list) and GET /users/123 (single resource). A DELETE sent to /users (the list URL) returns 405 because deleting a collection is not supported, whereas DELETE /users/123 would succeed.

CORS preflight 405 — OPTIONS not implemented. Browsers send an OPTIONS preflight request before cross-origin POST/PUT/DELETE. If the server does not handle OPTIONS, it returns 405, blocking the actual request. Add OPTIONS handling to every API endpoint.

Form submitting to the wrong URL. An HTML form uses method="POST" but submits to a URL that only handles GET. Some frameworks return 405 when form POST goes to a GET-only route.

Framework examples

Express.js — handle OPTIONS for CORS:

const cors = require('cors'); app.use(cors()); // automatically handles OPTIONS preflights // Or manually: app.options('/api/resource', (req, res) => { res.set('Allow', 'GET, POST, OPTIONS'); res.set('Access-Control-Allow-Methods', 'GET, POST'); res.sendStatus(204); }); app.get('/api/resource', handler); app.post('/api/resource', handler);

Django REST Framework — return 405 with Allow header:

from rest_framework.views import APIView from rest_framework.response import Response class ArticleView(APIView): http_method_names = ['get', 'post', 'head', 'options'] # DRF automatically returns 405 + Allow header for unlisted methods def get(self, request): return Response({"articles": []}) def post(self, request): return Response({"created": True}, status=201)

nginx — reject non-allowed methods:

location /api/webhook { if ($request_method !~ ^(POST|OPTIONS)$) { add_header Allow "POST, OPTIONS" always; return 405; } proxy_pass http://backend; }

405 vs 501 vs 403

CodeServer knows method?Resource supports it?Permission?
405YesNoN/A
501NoN/AN/A
403YesYesNo

Frequently asked questions

Why does my browser show 405 on form submit?

The form is POSTing to a URL that only accepts GET, or the server route is configured for GET only. Check the form's action URL and ensure the server route for that URL accepts POST. In many frameworks, GET routes and POST routes are registered separately.

Is OPTIONS always allowed on every endpoint?

Not required by the HTTP spec, but recommended for any API that needs to support CORS. Most REST frameworks respond to OPTIONS automatically with the supported methods. Include OPTIONS in the Allow: header of 405 responses so browsers know preflight is supported.

Should DELETE on a collection endpoint return 405 or 403?

405 if the API design does not support bulk deletion via DELETE on the collection URL (the method is simply not allowed for that resource). 403 if bulk deletion is a valid operation but the authenticated user lacks permission. The distinction is design intent vs. authorization.

Can 405 be returned for HEAD requests?

Technically yes, but RFC 9110 states that any resource supporting GET must also support HEAD. HEAD is the same as GET but without a response body. A resource that returns 405 for HEAD but 200 for GET is violating the specification. Ensure any endpoint that handles GET also handles HEAD (most frameworks do this automatically).

Related guides

HTTP 501 · HTTP 403 · HTTP 400 · HTTP 415 · HTTP 406

Client Errors Hub · All Guides · Home