caddyserver/caddy · critical
parsing root certificate PEM: %v
Error message
parsing root certificate PEM: %v
What it means
A root certificate PEM was loaded from storage (so storage is healthy) but pemDecodeCertificate could not parse it into an x509.Certificate. This means the stored root.crt bytes are not a valid PEM CERTIFICATE block or not a parseable certificate — i.e. the asset is corrupt or was overwritten with different content.
Source
Thrown at modules/caddypki/ca.go:301
return rootChain[0], rootSigner, nil
}
rootCertPEM, err := ca.storage.Load(ca.ctx, ca.storageKeyRootCert())
if err != nil {
if !errors.Is(err, fs.ErrNotExist) {
return nil, nil, fmt.Errorf("loading root cert: %v", err)
}
// TODO: should we require that all or none of the assets are required before overwriting anything?
rootCert, rootKey, err = ca.genRoot()
if err != nil {
return nil, nil, fmt.Errorf("generating root: %v", err)
}
}
if rootCert == nil {
rootCert, err = pemDecodeCertificate(rootCertPEM)
if err != nil {
return nil, nil, fmt.Errorf("parsing root certificate PEM: %v", err)
}
}
if rootKey == nil {
rootKeyPEM, err := ca.storage.Load(ca.ctx, ca.storageKeyRootKey())
if err != nil {
return nil, nil, fmt.Errorf("loading root key: %v", err)
}
rootKey, err = certmagic.PEMDecodePrivateKey(rootKeyPEM)
if err != nil {
return nil, nil, fmt.Errorf("decoding root key: %v", err)
}
}
return rootCert, rootKey, nil
}
func (ca CA) genRoot() (rootCert *x509.Certificate, rootKey crypto.Signer, err error) {
repl := ca.newReplacer()View on GitHub (pinned to 50e54ee279)
Solutions
- Inspect the stored root cert (openssl x509 -in root.crt -noout) to confirm corruption; then restore a known-good copy or delete the CA directory in storage so Caddy regenerates root+intermediate.
- If regenerated, re-install trust: caddy untrust && caddy trust (or redistribute the new root to clients) and restart clients relying on old certs.
- Check disk space/storage health so Store() cannot half-write assets again.
- Avoid hand-editing storage; mount storage read-only to humans if unintended edits recur.
Defensive patterns
Strategy: validation
Validate before calling
// Validate stored root before Caddy starts (cron/pre-start hook)
pem, err := os.ReadFile(rootCertPath)
if err == nil {
if _, err := pemDecodeOneCert(pem); err != nil {
log.Fatalf("stored root cert corrupt: %v", err)
}
} Type guard
func isParseableCertPEM(pemBytes []byte) bool {
block, _ := pem.Decode(pemBytes)
if block == nil || block.Type != "CERTIFICATE" { return false }
_, err := x509.ParseCertificate(block.Bytes)
return err == nil
} Try / catch
if err != nil {
if strings.Contains(err.Error(), "parsing root certificate PEM") {
// quarantine CA dir, restore backup or allow regeneration, restart
}
return err
} Prevention
- Never hand-edit files under Caddy's storage directory; use export/import APIs.
- Checksum and verify storage after restores or migrations.
- Monitor disk space so writes cannot truncate PEM assets.
When it happens
Trigger: storage.Load returns bytes that fail pem/x509 parsing: truncated file, PEM block of the wrong type (e.g. a key stored in root.crt), base64 corruption, or a text editor inserting CRLF/BOM. Occurs on any CA load where the root already exists (second start, reload, new authority for an internal issuer).
Common situations: Manual edits to storage/caddy/pki/<id>/ca/root.crt; failed writes (disk full during a previous store); scripts copying the wrong file over root.crt; storage replication that mangled the object.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- decoding intermediate certificate PEM: %v
- initializing certificate authority: %v
- loading root cert: %v
- generating root: %v
- decoding root key: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/85a612fb266c1fcd.
Report an issue: GitHub.