1. Library
  2. Http and the Web
  3. Status Codes

Updated 10 hours ago

The server understood your request perfectly. It just won't do it that way.

That's what 405 Method Not Allowed means. The endpoint exists. The server recognized what you asked for. But the HTTP method you used—DELETE, POST, PUT, whatever—isn't something this endpoint accepts. You knocked on the right door, but you asked the wrong question.

The Shape of a 405

When you hit a 405, the response tells you what went wrong and how to fix it:

HTTP/1.1 405 Method Not Allowed
Allow: GET, POST
Content-Type: application/json

{
    "error": "Method Not Allowed",
    "message": "DELETE method is not supported for this endpoint",
    "allowedMethods": ["GET", "POST"]
}

That Allow header isn't optional decoration—it's required by the HTTP spec. The server must tell you which methods it will accept. This is the server being helpful: "You can't DELETE here, but you can GET or POST."

Why Endpoints Refuse Methods

Some endpoints are read-only by design:

POST /api/status HTTP/1.1

HTTP/1.1 405 Method Not Allowed
Allow: GET

The status endpoint exists to report information, not receive it. POST makes no sense here.

Some resources shouldn't be deleted through the API:

DELETE /api/users HTTP/1.1

HTTP/1.1 405 Method Not Allowed
Allow: GET, POST

You can list users (GET) and create users (POST), but bulk deletion isn't exposed. Maybe it's a safety measure. Maybe deletion happens through a different process. The endpoint decides what operations make sense for its purpose.

Four Kinds of Refusal

HTTP has several ways to say no, and they mean different things:

404 Not Found: "I don't know what you're talking about."

GET /api/nonexistent
HTTP/1.1 404 Not Found

The endpoint doesn't exist at all.

405 Method Not Allowed: "I know what you want, but I won't do it that way."

DELETE /api/users
HTTP/1.1 405 Method Not Allowed
Allow: GET, POST

The endpoint exists but doesn't accept this method.

403 Forbidden: "You specifically aren't allowed to do this."

DELETE /api/users/123
HTTP/1.1 403 Forbidden

The method might be valid, but you lack permission.

501 Not Implemented: "I don't even know what that method is."

WEIRDMETHOD /api/users
HTTP/1.1 501 Not Implemented

The server doesn't recognize the HTTP method itself.

The distinction matters for debugging. A 404 means check your URL. A 405 means check your method. A 403 means check your credentials. A 501 means you're probably doing something unusual.

Implementing 405 Properly

The pattern is straightforward—define the methods you support, reject everything else:

app.route('/api/users')
    .get(function(request, response) {
        response.json(users);
    })
    .post(function(request, response) {
        createUser(request.body);
        response.status(201).json({success: true});
    })
    .all(function(request, response) {
        response.status(405)
            .set('Allow', 'GET, POST, OPTIONS')
            .json({
                error: 'Method Not Allowed',
                allowedMethods: ['GET', 'POST', 'OPTIONS']
            });
    });

The .all() handler catches any method not explicitly defined above it. Every 405 response includes the Allow header—this isn't just good practice, it's required.

Don't Forget OPTIONS

The OPTIONS method asks "what can I do here?" Servers should answer:

OPTIONS /api/users HTTP/1.1

HTTP/1.1 204 No Content
Allow: GET, POST, PUT, DELETE, OPTIONS

This is how CORS preflight requests work—the browser asks OPTIONS before making cross-origin requests. If your server returns 405 for OPTIONS, you'll break CORS for clients trying to use your API from browsers.

Handling 405 as a Client

When you receive a 405, the Allow header tells you what to do instead:

async function makeRequest(url, method, data) {
    const response = await fetch(url, {
        method: method,
        headers: { 'Content-Type': 'application/json' },
        body: data ? JSON.stringify(data) : undefined
    });

    if(response.status === 405) {
        const allowHeader = response.headers.get('Allow');
        const allowedMethods = allowHeader ? allowHeader.split(', ') : [];
        
        throw new Error(
            `${method} not allowed. Try: ${allowedMethods.join(', ')}`
        );
    }

    return response;
}

RESTful Method Semantics

In REST, each method has a specific meaning:

  • GET: Retrieve resources (safe, idempotent)
  • POST: Create new resources
  • PUT: Replace resources entirely (idempotent)
  • PATCH: Update resources partially
  • DELETE: Remove resources (idempotent)

Endpoints should only accept methods that make semantic sense:

// Collection: list and create
app.route('/api/users')
    .get(listUsers)
    .post(createUser)
    .all(methodNotAllowed(['GET', 'POST', 'OPTIONS']));

// Individual resource: read, update, delete
app.route('/api/users/:id')
    .get(getUser)
    .put(replaceUser)
    .patch(updateUser)
    .delete(deleteUser)
    .all(methodNotAllowed(['GET', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']));

You can't DELETE a collection (that would be dangerous). You can't POST to a specific resource (POST creates new things, it doesn't modify existing ones). These restrictions aren't arbitrary—they're how REST maintains predictable semantics.

Frequently Asked Questions About 405 Method Not Allowed

Was this page helpful?

😔
🤨
😃
405 Method Not Allowed • Library • Connected