← Debugging Guides

阅读中文版本

HTTP 405 Method Not Allowed — Wrong Verb

Fix 405 Method Not Allowed by matching the HTTP verb to the route, checking the server Allow header, and correcting client or proxy method handling.

beginnerdebugginghttpstatus-codesrest

Symptoms

  • The API returns 405 with "Method Not Allowed" for a route that exists
  • GET works but POST returns 405
  • A proxy or preflight changes the method the server sees

Possible causes

  • The route is registered for different verbs than the client uses
  • The client sends a verb the handler does not implement (undefined POST on a GET route)
  • A trailing slash or proxy rewrite maps the request to a different route

Diagnosis steps

Read the Allow header

curl -i -X POST https://api.example.com/items

Interpretation

The Allow header lists the methods the route actually supports, revealing the correct verb.

Compare route registration with the request

grep -rn "app.get\|app.post\|router.put" src/routes

Interpretation

Confirming the registered verbs against the client call finds the mismatch.

Root cause

The server found a route matching the path but not the HTTP method, so it responds 405 and advertises the allowed methods in the Allow header. The path exists; the verb is wrong.

Fix

Use the verb the route declares, register the needed method if the operation is legitimate, and ensure proxies and clients preserve the intended method (PATCH versus PUT, POST versus GET).

Risk note

Changing a GET route to accept POST to silence the error can break caching and idempotency semantics.

Verify the fix

Send the request with the correct verb and confirm 2xx; verify a wrong verb still returns 405 with an accurate Allow header.

Symptoms

This debugging guide addresses “HTTP 405 Method Not Allowed — Wrong Verb”. Start from the symptoms, follow the ordered diagnostics, and confirm each hypothesis before moving on; the fix and verification steps then close the loop.

Observed symptoms include:

  • The API returns 405 with “Method Not Allowed” for a route that exists
  • GET works but POST returns 405
  • A proxy or preflight changes the method the server sees

Reproduce and Diagnose

Reproduce the failure in isolation before changing any code. Work through the checks below in order; each one narrows the search space.

Step 1: Read the Allow header

curl -i -X POST https://api.example.com/items

The Allow header lists the methods the route actually supports, revealing the correct verb.

Step 2: Compare route registration with the request

grep -rn "app.get\|app.post\|router.put" src/routes

Confirming the registered verbs against the client call finds the mismatch.

Likely contributors, in order of frequency:

  • The route is registered for different verbs than the client uses
  • The client sends a verb the handler does not implement (undefined POST on a GET route)
  • A trailing slash or proxy rewrite maps the request to a different route

Root Cause

The server found a route matching the path but not the HTTP method, so it responds 405 and advertises the allowed methods in the Allow header. The path exists; the verb is wrong.

The Fix

Use the verb the route declares, register the needed method if the operation is legitimate, and ensure proxies and clients preserve the intended method (PATCH versus PUT, POST versus GET).

Watch out: Changing a GET route to accept POST to silence the error can break caching and idempotency semantics.

// Express: register the needed verb explicitly
router.get('/items', listItems);
router.post('/items', createItem);

// client: use the verb the route declares
await fetch('/items', { method: 'POST', body: JSON.stringify(payload) });

# inspect allowed methods
curl -i -X OPTIONS https://api.example.com/items

Verify and Prevent

Send the request with the correct verb and confirm 2xx; verify a wrong verb still returns 405 with an accurate Allow header.

Once verified, add a regression test that reproduces the original symptom so the failure cannot silently return.

This class of failure is usually environmental rather than pure logic, so capture the exact command, the environment variables, and the working directory in your bug report. Reproduce it in the smallest possible script, then widen the scope only once the minimal case is understood. A short written checklist for this failure mode saves hours the next time it appears.