caddyserver/caddy · error · caddy.APIError
failed to provision CA %s, %w
Error message
failed to provision CA %s, %w
What it means
A 500 caddy.APIError returned when the default CA (`local`) was requested but not yet configured, so the admin API tries to provision it on demand (ca.Provision) and that fails. Provisioning generates/loads the root and intermediate from storage, so failures are storage errors (cannot write keys/certs), crypto errors, or missing dependencies. The underlying error is wrapped with %w.
Source
Thrown at modules/caddypki/adminapi.go:212
// provision it, because the user probably aims to
// change their config to enable PKI immediately after
// if they actually requested the local CA ID.
if !ok {
if id != DefaultCAID {
return nil, caddy.APIError{
HTTPStatus: http.StatusNotFound,
Err: fmt.Errorf("no certificate authority configured with id: %s", id),
}
}
// Provision the default CA, which generates and stores a root
// certificate in storage, if one doesn't already exist.
ca = new(CA)
err := ca.Provision(a.ctx, id, a.log)
if err != nil {
return nil, caddy.APIError{
HTTPStatus: http.StatusInternalServerError,
Err: fmt.Errorf("failed to provision CA %s, %w", id, err),
}
}
}
return ca, nil
}
func rootAndIntermediatePEM(ca *CA) (root, inter []byte, err error) {
root, err = pemEncodeCert(ca.RootCertificate().Raw)
if err != nil {
return root, inter, err
}
for _, interCert := range ca.IntermediateCertificateChain() {
pemBytes, err := pemEncodeCert(interCert.Raw)
if err != nil {
return nil, nil, err
}View on GitHub (pinned to 50e54ee279)
Solutions
- Read the wrapped cause in the response body — it distinguishes storage errors from crypto errors
- Fix storage access: permissions on the storage root (chown to the Caddy user), connectivity/credentials for custom storage modules
- If provisioning genuinely failed midway, remove the partial CA resources under the storage (pki directories) and retry the request to regenerate
- Alternatively configure the pki app explicitly in config so provisioning happens (and fails loudly) at load time with fuller logs
Example fix
# before: storage dir owned by root, default CA fails to provision curl http://localhost:2019/pki/ca/local # 500 failed to provision CA local # after sudo chown -R caddy:caddy /var/lib/caddy # or the storage root in use curl http://localhost:2019/pki/ca/local
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight storage writability before first use of the default CA:
func storageWritable() error {
dir := filepath.Join(caddy.AppDataDir())
f, err := os.CreateTemp(dir, "pki-probe-*")
if err != nil { return fmt.Errorf("storage not writable: %w", err) }
f.Close()
os.Remove(f.Name())
return nil
} Try / catch
// On 500 'failed to provision CA', read the wrapped cause before acting:
if resp.StatusCode == 500 && strings.Contains(string(body), "failed to provision") {
// storage/permission issue — fix environment, then retry the same GET
return fmt.Errorf("default CA provisioning failed: %s; check storage perms", body)
} Prevention
- Declare the pki app explicitly in production configs so provisioning errors surface at load time with full logs
- Ensure the storage root is writable by the Caddy user from first start
- Back up the default CA's root key once generated
When it happens
Trigger: GET /pki/ca/local (or /pki/ca/local/certificates) with no pki app configured, where Provision fails: storage backend error writing the root key, permission-denied on the storage directory, or a root cert in storage without a parseable key. The handler constructs ca = new(CA) and calls Provision with the admin context.
Common situations: First request to the admin PKI endpoint on a fresh install whose storage dir is root-owned or read-only; custom storage module (e.g. consul/redis) unreachable at that moment; storage resources half-written after a crash; running with an old root key file format.
Related errors
- failed to get root and intermediate cert for CA %s: %v
- --input is required
- no metrics registry found
- provisioning admin router module %s: %v
- loading new config: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/7fcab27f53714e90.
Report an issue: GitHub.