HTTP 501 is Not Implemented: the server doesn’t support the functionality the request needs (RFC 9110 section 15.6.2). RFC 9110 names the case it’s for: a request method the server doesn’t recognize and can’t support for any resource. RFC 9112 adds two more: a method longer than any the server implements, and a Transfer-Encoding it doesn’t understand.
Who sends it
- Python’s
http.serveranswers any method its handler has nodo_method for, sopython3 -m http.serveranswers a POST with501 Unsupported method ('POST'). - Apache httpd answers a method it doesn’t know with a 501 page titled “Method Not Implemented”.
- nginx and Go’s server answer a request whose
Transfer-Encodingisn’tchunkedwith 501, as RFC 9112 asks.
Node.js is the odd one out: its HTTP parser knows a fixed list of methods, http.METHODS, and rejects any other with 400 before your code runs.
501, 405, 503 or 404
a method the server doesn't know, for any resource 501 Not Implemented
a known method this resource doesn't accept 405 Method Not Allowed, with Allow
a feature switched off for now 503 Service Unavailable
an endpoint that doesn't exist (yet) 404 Not Found
RFC 9110 section 9.1 draws the first line: an unrecognized or unimplemented method is 501, a recognized one the target doesn’t allow is 405.
Caching: a 501 can stick
501 is heuristically cacheable, the only 5xx on RFC 9110’s list. Caches store responses to GET and HEAD, so a GET endpoint that answers 501 “until we ship it” can be kept by browsers and CDNs and served after the feature goes live. Send Cache-Control: no-store with any 501 that isn’t permanent.
Gotchas
- It’s a 5xx. Monitoring counts it as a server error, and crawlers treat it as one. A placeholder route is better off as a 404 until it exists.
- Clients don’t retry it, and shouldn’t: the same request gets the same answer.
switch r.Method {
case http.MethodGet, http.MethodHead:
serve(w, r)
case http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete:
w.Header().Set("Allow", "GET, HEAD")
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
default:
http.Error(w, "not implemented", http.StatusNotImplemented)
}
app.get('/api/reports/:id/pdf', (req, res) => { // Express: a feature that isn't there yet
res.status(501).set('Cache-Control', 'no-store').json({ error: 'PDF export is not available yet' });
});
Search 405 501 in the tool below to compare the two.