---
title: "405 Method Not Allowed: What It Means and How to Fix It Fast"
url: https://apyhub.com/blog/405-method-not-allowed
author: Muskan Sidana
published: 2025-04-16T00:00:00Z
tags: [engineering]
---

# 405 Method Not Allowed: What It Means and How to Fix It Fast

# 405 Method Not Allowed: What It Means and How to Fix It

## Introduction

A **405 Method Not Allowed** error means the server understood your request and recognizes the HTTP method you used — GET, POST, PUT, DELETE — but that method isn't permitted on the resource you called. The route exists; the verb is wrong for it.

The quickest tell is in the response itself. Per the HTTP specification (RFC 9110, §15.5.6), a server returning 405 **must** include an `Allow` header listing the methods the resource does accept. That header is the fix hiding in plain sight — it tells you exactly which method to switch to.

Here's a 405 in practice. You send a `POST` to a read-only endpoint:

```http
POST /api/data HTTP/1.1
Host: example.com
Content-Type: application/json

{"key": "value"}
```

The server responds:

```http
HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD
Content-Type: text/html
```

Translation: this resource takes `GET` or `HEAD`, not `POST`. The error isn't the hard part — figuring out *why* the method is blocked, when the endpoint, the server config, and a framework router can all be the cause, is where the time goes.

## What a 405 Actually Means

HTTP methods define the action a request performs: `GET` reads, `POST` creates, `PUT` and `PATCH` update, `DELETE` removes. Every resource on a server declares which of those it supports. When your method isn't on that list, the server rejects the request with a 405 rather than attempting it.

The distinction that trips people up: a 405 is not "the server broke" and not "the page doesn't exist." The server is working correctly and the resource *is* there. It's specifically saying *this verb is not valid here* — and it's obligated to tell you which verbs are.

## 405 vs 400, 401, 403, 404, and 501

405 is easy to confuse with the status codes around it. They fail for genuinely different reasons, and reading the wrong one sends you debugging the wrong thing:

| Code    | Name            | What it actually means                                                               | How it differs from 405                                                                                                             |
| ------- | --------------- | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- |
| **400** | Bad Request     | The request itself is malformed — bad syntax, invalid JSON, missing required fields. | The *verb* is fine; the *content* is broken. A 405 is a well-formed request with the wrong method.                                  |
| **401** | Unauthorized    | Authentication is missing or failed.                                                 | 401 is about *who you are*. 405 doesn't care who you are — the method is wrong for everyone.                                        |
| **403** | Forbidden       | You're authenticated but not permitted to do this.                                   | 403 is a *permission* decision on an allowed action. 405 means the action (method) itself isn't allowed on the resource.            |
| **404** | Not Found       | The resource or route doesn't exist.                                                 | 404 \= the path is wrong. 405 \= the path is right, the method is wrong.                                                            |
| **501** | Not Implemented | The server doesn't support the method *at all*, for any resource.                    | 501 is server-wide ("we don't do PATCH here, anywhere"). 405 is resource-specific ("this endpoint doesn't do PATCH, others might"). |

If you remember one line: **404 means the door isn't there; 405 means the door is there but locked to that knock.**

## What Triggers a 405

The error surfaces in a handful of recurring situations:

1. **Wrong HTTP method for the endpoint.** REST APIs are strict. `/users` might accept `POST` to create a record but reject `PUT` because updates happen at `/users/{id}`. Sending the right verb to the wrong level still returns 405.
2. **Server configuration blocking the method.** Apache and Nginx can restrict methods at the config level. A rule meant to lock down `DELETE` or `PUT` for safety can overreach and block legitimate traffic.
3. **API endpoint rules.** A `GET`-only endpoint hit with `DELETE` returns an immediate 405. This is the endpoint enforcing its own contract, and it's easy to miss when the docs aren't in front of you.
4. **Security filtering.** Web Application Firewalls (WAFs) like Cloudflare sometimes block methods such as `TRACE`, `OPTIONS`, or `PATCH` to reduce attack surface — producing 405s even when the origin server would have allowed the method.
5. **Framework routing gaps.** In most web frameworks, a route registered for one method won't answer another. Depending on the framework, sending the wrong verb returns either a 405 or a 404 (more on that below).

## How to Fix a 405 Method Not Allowed Error

The fix is always: find the cause, then correct the request or the config. Work through these in order.

### 1. Confirm which method the endpoint expects

Read the `Allow` header on the 405 response first — it lists the valid methods. If you don't have one, probe the endpoint with `OPTIONS`:

```bash
curl -X OPTIONS https://api.example.com/users -i
```

A typical response:

```http
HTTP/1.1 200 OK
Allow: GET, POST, HEAD
```

Match your request to that list. If it says `Allow: POST` and you were sending `PUT`, that's your answer.

### 2. Check the server configuration

If the endpoint *should* accept your method but doesn't, inspect the server config.

**Apache** — look for `Limit` directives in `.htaccess` or `httpd.conf`:

```apache
<Limit GET POST PUT>
    Order Allow,Deny
    Allow from all
</Limit>
```

**Nginx** — check `limit_except` in the relevant `location` block:

```nginx
location /api {
    limit_except GET POST DELETE {
        deny all;
    }
}
```

Reload after changes (`systemctl reload apache2` or `nginx -s reload`).

### 3. Check security filters and WAF rules

If a WAF sits in front of the origin, review its ruleset — it may be stripping methods before they reach your server. Whitelist the legitimate method rather than disabling the rule wholesale, so you don't trade a 405 for an actual vulnerability.

### 4. Fix the framework route

Make sure a handler exists for the method you're sending. In Express:

```javascript
app.delete('/posts/:id', (req, res) => {
  // delete logic
});
```

No `DELETE` handler means no valid response for that verb.

### 5. Rule out permissions

If the method is allowed but tied to a role, a missing or wrong token can produce a 405 or 403. Send the request with auth attached and compare:

```bash
curl -X DELETE https://api.example.com/posts/1 \
  -H "Authorization: Bearer <token>" -i
```

### 6. Read the server logs

Logs tell you whether the block came from config or from the method itself. Nginx (`/var/log/nginx/error.log`):

```
2026/06/30 10:00:00 [error] 1234#0: *1 method not allowed
```

Apache (`/var/log/apache2/error.log`):

```
[Tue Jun 30 10:00:00.2026] [error] Method PUT not allowed for /api/data
```

Follow the trail from there to the config line or route responsible.

## Framework-Specific 405s (and the "works in the browser, fails in the client" case)

A recurring source of confusion: the *same URL* behaves differently depending on what sends the request. Pasting a URL into a browser issues a `GET`. An API client — Postman, curl, Voiden — can issue `POST`, `PUT`, or `DELETE`. So a route that only accepts `GET` will load fine in a browser and then return a 405 (or a 404) the moment a client sends a different verb. If a request "works in the browser but not in the client," check the method before anything else.

How different stacks report the same underlying problem:

* **Laravel / Symfony** throw `MethodNotAllowedHttpException` (from `Symfony\Component\HttpKernel\Exception`) when the path matches a route but the HTTP method doesn't. Seeing `MethodNotAllowedHttpException` in a stack trace is the framework telling you the route exists for a *different* verb — check your `Route::` definitions or the controller's allowed methods.
* **Spring** raises `HttpRequestMethodNotSupportedException`, mapped to 405, when no handler matches the request method.
* **Django REST Framework** returns its `MethodNotAllowed` exception as a 405 when a viewset doesn't implement the method.
* **Express** is the exception worth knowing: by default it does *not* return 405 for an unhandled method — it falls through to a 404 (`Cannot POST /posts`). To get a proper 405 with an `Allow` header, you handle it explicitly (for example with `app.all()` on the route, or a router that tracks registered methods). If you expected a 405 and got a 404 in Node, this is usually why.

## Testing and Reproducing a 405

Reproducing the error deliberately is the fastest way to confirm the cause. Three tools cover most workflows:

* **curl** — the quickest way to fire a single request with an explicit method and read the raw `Allow` header. Ideal for one-off checks:
  ```bash
  curl -X PUT https://api.example.com/data -i
  ```
* **Postman** — a GUI client for sending requests across methods and inspecting responses, useful when you're clicking through an API interactively.
* [Voiden](https://voiden.md) — an offline-first, Git-native API client that stores requests as Markdown-based `.void` files you can version alongside your code. Because the requests live in your repo, the exact `POST`-vs-`PUT` call that triggered a 405 is committed, diffable, and reproducible by anyone who checks out the branch — rather than trapped in one person's local client. Voiden is open source (Apache 2.0); you can [download it here](https://voiden.md/download).

None of these fix the server — they let you see precisely which method the resource accepts, so you correct the request with certainty instead of guessing.

## Where ApyHub Fits

A large share of 405s in day-to-day work come from calling an endpoint with the wrong verb because the method contract wasn't obvious. That's a documentation-and-consistency problem as much as a coding one.

[ApyHub](https://apyhub.com/) is a certified API marketplace — a catalog of 200+ APIs and 1,000+ endpoints for the utility work most products need (file conversion, data validation, PDF processing, enrichment, and more). Every endpoint in the [catalog](https://apyhub.com/catalog) ships with a documented, machine-readable specification, including the methods it accepts, so the "which verb does this take" question is answered before you write the call — and answerable by AI agents consuming the catalog through MCP, not just humans reading docs. It doesn't make 405s impossible, but it removes one of the most common ways developers stumble into them: guessing at an undocumented method contract.

[**Explore the catalog →**](https://apyhub.com/catalog)

## Conclusion

A 405 Method Not Allowed error is a signal, not a mystery: the resource exists, the method doesn't fit it, and the `Allow` header is telling you what does. Confirm the expected method, check server config and WAF rules, verify your framework route, and read the logs — in that order — and the fix is usually a one-line change. The habit that prevents most of them is knowing an endpoint's method contract before you call it, rather than discovering it from a rejected request.

[**Try ApyHub →**](https://apyhub.com/)

## FAQ

### What exactly causes a 405 Method Not Allowed error?

The server recognizes your HTTP method but the specific resource you called doesn't permit it — for example, sending `DELETE` to an endpoint built only for `GET` and `POST`. The response includes an `Allow` header listing the methods that *are* accepted, which tells you what to switch to.

### How do I find out which HTTP methods an endpoint supports?

Read the `Allow` header on the 405 response, or send an `OPTIONS` request: `curl -X OPTIONS `[`https://api.example.com/resource`](https://api.example.com/resource)` -i`. The response's `Allow` header lists every method the endpoint accepts.

### What's the difference between a 403 and a 405 error?

A 403 Forbidden means you're not permitted to perform an action you're otherwise allowed to request — it's about authorization. A 405 means the HTTP method itself isn't valid for that resource, regardless of who you are.

### What's the difference between a 404 and a 405?

A 404 means the route or resource doesn't exist. A 405 means the route exists but doesn't accept the method you used. If you're getting a 404 when you expected a 405, your framework may be treating an unhandled method as a missing route (Express does this by default).

### Why does my request work in the browser but fail in Postman or curl?

A browser issues a `GET` when you load a URL, while an API client can send `POST`, `PUT`, or `DELETE`. A route that only allows `GET` will load in the browser and return a 405 (or 404) from the client. Check the method your client is sending first.

### What does MethodNotAllowedHttpException mean?

It's the exception Symfony and Laravel throw when a request's path matches a defined route but its HTTP method doesn't. Seeing it means the route exists for a different verb — check your route definitions and correct the method or add a handler for the one you're sending.

### Can a Web Application Firewall cause a 405 error?

Yes. WAFs such as Cloudflare may block methods like `TRACE`, `PATCH`, or `OPTIONS` to reduce attack surface, producing a 405 even when the origin server would allow the method. Review the WAF ruleset and whitelist the legitimate method rather than disabling the rule.

### How do I prevent 405 errors during development?

Validate each request against the endpoint's method contract before deploying, and keep those contracts documented and version-controlled so the whole team calls endpoints the same way. Consuming APIs whose specifications already declare their accepted methods removes the most common cause — guessing at an undocumented verb.
