{"record":{"id":"5363fb2529cde872","repo":"caddyserver/caddy","slug":"method-not-allowed-v","errorCode":null,"errorMessage":"method not allowed: %v","messagePattern":"method not allowed: (.+?)","errorType":"http","errorClass":"caddy.APIError","httpStatus":405,"severity":"info","filePath":"modules/caddypki/adminapi.go","lineNumber":98,"sourceCode":"\t\treturn a.handleCAInfo(w, r)\n\tcase len(parts) == 3 && parts[0] == \"ca\" && parts[1] != \"\" && parts[2] == \"certificates\":\n\t\treturn a.handleCACerts(w, r)\n\t}\n\treturn caddy.APIError{\n\t\tHTTPStatus: http.StatusNotFound,\n\t\tErr:        fmt.Errorf(\"resource not found: %v\", r.URL.Path),\n\t}\n}\n\n// handleCAInfo returns information about a particular\n// CA by its ID. If the CA ID is the default, then the CA will be\n// provisioned if it has not already been. Other CA IDs will return an\n// error if they have not been previously provisioned.\nfunc (a *adminAPI) handleCAInfo(w http.ResponseWriter, r *http.Request) error {\n\tif r.Method != http.MethodGet {\n\t\treturn caddy.APIError{\n\t\t\tHTTPStatus: http.StatusMethodNotAllowed,\n\t\t\tErr:        fmt.Errorf(\"method not allowed: %v\", r.Method),\n\t\t}\n\t}\n\n\tca, err := a.getCAFromAPIRequestPath(r)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\trootCert, interCert, err := rootAndIntermediatePEM(ca)\n\tif err != nil {\n\t\treturn caddy.APIError{\n\t\t\tHTTPStatus: http.StatusInternalServerError,\n\t\t\tErr:        fmt.Errorf(\"failed to get root and intermediate cert for CA %s: %v\", ca.ID, err),\n\t\t}\n\t}\n\n\trepl := ca.newReplacer()\n","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddypki/adminapi.go#L80-L116","documentation":"A 405 caddy.APIError returned by the PKI admin API's handleCAInfo when the request method is not GET. The /pki/ca/&lt;id&gt; endpoint is read-only: it returns CA metadata (id, name, common names, PEM certs), so POST/PUT/DELETE are rejected before any CA lookup happens. The error names the offending method.","triggerScenarios":"Sending POST/PUT/DELETE/PATCH to /pki/ca/&lt;id&gt; — for example a script trying to create or reconfigure a CA via the admin API. The method check is the first statement in the handler, so even a valid CA id returns 405 when the method is wrong.","commonSituations":"Assuming the admin API can create CAs (it cannot — CA creation is config-driven only); REST tooling defaulting to POST; retrying a GET with POST after a transient failure.","solutions":["Use GET for /pki/ca/&lt;id&gt;","To create or change a CA, edit the config (pki app in JSON / global options) and load it via the config admin endpoint instead","Check the response's Allow semantics: only GET is meaningful on this route"],"exampleFix":"# before\ncurl -X POST http://localhost:2019/pki/ca/local -d '{...}'\n\n# after\ncurl http://localhost:2019/pki/ca/local\n# to change the CA, load new config instead:\ncurl -X PUT http://localhost:2019/load -H 'Content-Type: application/json' -d @caddy.json","handlingStrategy":"validation","validationCode":"// Always issue GETs for CA info:\nreq, _ := http.NewRequest(http.MethodGet, base+\"/pki/ca/\"+id, nil)\n// never POST/PUT/DELETE on this route","typeGuard":null,"tryCatchPattern":"// Map 405 to a usage error in clients:\nif resp.StatusCode == http.StatusMethodNotAllowed {\n    return errors.New(\"PKI CA endpoints are read-only; use GET\")\n}","preventionTips":["Remember the PKI admin API is read-only for CA info","Use the /load endpoint to change CA configuration, not /pki/*","Default http clients to explicit methods, not verbs inherited from templates"],"tags":["pki","admin-api","http-405","read-only"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}