caddyserver/caddy · warning · caddy.APIError
method not allowed
Error message
method not allowed
What it means
The admin API endpoint GET /reverse_proxy/upstreams (which reports the state of the reverse proxy upstream pool) rejects any HTTP method other than GET with 405 Method Not Allowed, wrapped in a caddy.APIError.
Source
Thrown at modules/caddyhttp/reverseproxy/admin.go:66
}
// Routes returns a route for the /reverse_proxy/upstreams endpoint.
func (al adminUpstreams) Routes() []caddy.AdminRoute {
return []caddy.AdminRoute{
{
Pattern: "/reverse_proxy/upstreams",
Handler: caddy.AdminHandlerFunc(al.handleUpstreams),
},
}
}
// handleUpstreams reports the status of the reverse proxy
// upstream pool.
func (adminUpstreams) handleUpstreams(w http.ResponseWriter, r *http.Request) error {
if r.Method != http.MethodGet {
return caddy.APIError{
HTTPStatus: http.StatusMethodNotAllowed,
Err: fmt.Errorf("method not allowed"),
}
}
// Prep for a JSON response
w.Header().Set("Content-Type", "application/json")
enc := json.NewEncoder(w)
// Collect the results to respond with
results := []upstreamStatus{}
knownHosts := make(map[string]struct{})
// Iterate over the static upstream pool (needs to be fast)
var rangeErr error
hosts.Range(func(key, val any) bool {
address, ok := key.(string)
if !ok {
rangeErr = caddy.APIError{
HTTPStatus: http.StatusInternalServerError,View on GitHub (pinned to 50e54ee279)
Solutions
- Use a plain GET request: 'curl localhost:2019/reverse_proxy/upstreams'.
- Remove -X POST/-d flags from monitoring/health-check commands hitting read-only admin endpoints.
- Treat a 405 from this endpoint as a client bug, not a server problem.
Example fix
# before
curl -X POST http://localhost:2019/reverse_proxy/upstreams -d '{}'
# after
curl http://localhost:2019/reverse_proxy/upstreams Defensive patterns
Strategy: validation
Validate before calling
// client side: never send a body or non-GET method to this endpoint
req, _ := http.NewRequest(http.MethodGet, adminURL+"/reverse_proxy/upstreams", nil)
// server side (if wrapping admin endpoints):
if r.Method != http.MethodGet {
w.Header().Set("Allow", http.MethodGet)
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
} Try / catch
resp, err := http.Get(url)
if err == nil && resp.StatusCode == http.StatusMethodNotAllowed {
// fix the caller: this endpoint is read-only GET
log.Print("/reverse_proxy/upstreams is GET-only; remove -X/-d from the request")
} Prevention
- Treat admin read endpoints as GET-only by convention.
- Review curl invocations before adding -X or -d flags.
- Check the Allow header on 405s to learn the accepted method.
When it happens
Trigger: Sending POST, PUT, DELETE, etc. to the admin endpoint on the admin listener, e.g. 'curl -X POST localhost:2019/reverse_proxy/upstreams'.
Common situations: Monitoring scripts that default to POST with a JSON body; curl invocations with -X flags copied from write-style admin endpoints like /load.
Related errors
- no metrics registry found
- provisioning admin router module %s: %v
- loading identity issuer modules: %s
- access control %d public key %d: parsing base64 certificate
- cannot enable remote admin without a certificate cache; conf
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/6d0fe7bb8b3328dd.
Report an issue: GitHub.