caddyserver/caddy · error
CA %s has no root certificate
Error message
CA %s has no root certificate
What it means
During pki_root pool provisioning, ca.RootCertificate() returned nil for a resolved CA, meaning the CA exists but has no root certificate material available yet. The pool cannot trust a CA whose root has not been generated or loaded.
Source
Thrown at modules/caddytls/capools.go:251
pkiApp, err := ctx.AppIfConfigured("pki")
if err != nil {
return fmt.Errorf("pki_root CA pool requires that a PKI app is configured: %v", err)
}
pki := pkiApp.(*caddypki.PKI)
for _, caID := range p.Authority {
c, err := pki.GetCA(ctx, caID)
if err != nil || c == nil {
return fmt.Errorf("getting CA %s: %v", caID, err)
}
p.ca = append(p.ca, c)
}
caPool := x509.NewCertPool()
var certs []*x509.Certificate
for _, ca := range p.ca {
rootCert := ca.RootCertificate()
if rootCert == nil {
return fmt.Errorf("CA %s has no root certificate", ca.ID)
}
caPool.AddCert(rootCert)
certs = append(certs, rootCert)
}
p.pool = caPool
p.certs = certs
return nil
}
// Syntax:
//
// trust_pool pki_root [<ca_name>...] {
// authority <ca_name>...
// }
//
// The 'authority' directive can be specified multiple times.
func (pkir *PKIRootCAPool) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {View on GitHub (pinned to 50e54ee279)
Solutions
- Inspect the `root` sub-directive of the CA in the pki block: if it points at a cert file, ensure the file exists, is a valid PEM certificate, and is readable by Caddy.
- Remove stale/partial internal CA data from storage (e.g. the PKI app's storage keys) so the root is regenerated cleanly, then reload.
- If embedding Caddy programmatically, ensure the pki app is fully provisioned before the caddytls app references its CAs.
Example fix
# before
{
pki {
ca custom {
root { cert /etc/caddy/missing-root.crt key /etc/caddy/missing-root.key }
}
}
}
# after (let Caddy manage the root, or point at existing files)
{
pki {
ca custom {
root { cert /etc/caddy/root.crt key /etc/caddy/root.key }
}
}
} Defensive patterns
Strategy: validation
Validate before calling
// when embedding Caddy, confirm the CA has a root before provisioning caddytls
if ca, err := pkiApp.GetCA(ctx, "local"); err == nil && ca != nil {
if ca.RootCertificate() == nil {
return fmt.Errorf("CA %s not ready: install or generate its root first", ca.ID)
}
} Try / catch
// if you drive provisioning manually, surface the error and stop rather than continuing
if err := pool.Provision(ctx); err != nil {
log.Printf("trust pool provisioning failed: %v", err)
return err // do not fall back to an empty pool
} Prevention
- When supplying custom root cert files, ship both cert and key files together and verify readability before starting Caddy.
- Back up the internal CA storage so roots are never partially lost.
- Test config changes in staging where the internal CA state mirrors production.
When it happens
Trigger: The PKI app created the CA object lazily via GetCA but the root key/certificate have not been installed (root generation failed or was deferred), or a custom CA was configured with external/root-less settings so no root certificate exists at provision time.
Common situations: A pki CA defined with a missing or unreadable root certificate file path; storage backing the internal CA was wiped or is read-only; interleaving of provisioning order in unusual programmatic embedding of Caddy.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- pki_root CA pool requires that a PKI app is configured: %v
- pki_intermediate CA pool requires that a PKI app is configur
- CA %s has a nil certificate in its intermediate chain
- --input is required
- getting CA %s: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/0ed224604852da62.
Report an issue: GitHub.