caddyserver/caddy · critical
decoding intermediate certificate PEM: %v
Error message
decoding intermediate certificate PEM: %v
What it means
An intermediate certificate PEM was loaded from storage, but pemDecodeCertificateChain could not parse it into a chain of x509 certificates. The stored intermediate.crt is corrupt, truncated, or contains a non-certificate PEM block. Because the intermediate is what signs leafs, this stops all issuance even though the root is fine.
Source
Thrown at modules/caddypki/ca.go:365
interCertPEM, err := ca.storage.Load(ca.ctx, ca.storageKeyIntermediateCert())
if err != nil {
if !errors.Is(err, fs.ErrNotExist) {
return nil, nil, fmt.Errorf("loading intermediate cert: %v", err)
}
// TODO: should we require that all or none of the assets are required before overwriting anything?
interCert, interKey, err = ca.genIntermediate(rootCert, rootKey)
if err != nil {
return nil, nil, fmt.Errorf("generating new intermediate cert: %v", err)
}
interCertChain = append(interCertChain, interCert)
}
if len(interCertChain) == 0 {
interCertChain, err = pemDecodeCertificateChain(interCertPEM)
if err != nil {
return nil, nil, fmt.Errorf("decoding intermediate certificate PEM: %v", err)
}
}
if interKey == nil {
interKeyPEM, err := ca.storage.Load(ca.ctx, ca.storageKeyIntermediateKey())
if err != nil {
return nil, nil, fmt.Errorf("loading intermediate key: %v", err)
}
interKey, err = certmagic.PEMDecodePrivateKey(interKeyPEM)
if err != nil {
return nil, nil, fmt.Errorf("decoding intermediate key: %v", err)
}
}
return interCertChain, interKey, nil
}
func (ca CA) genIntermediate(rootCert *x509.Certificate, rootKey crypto.Signer) (interCert *x509.Certificate, interKey crypto.Signer, err error) {View on GitHub (pinned to 50e54ee279)
Solutions
- Verify and, if corrupt, delete only the intermediate cert+key objects in storage (keep root) and restart — Caddy will regenerate a fresh intermediate signed by the existing root, and existing leafs remain valid until expiry.
- Restore a known-good intermediate.crt/key.pem pair from backup instead, if you need continuity of the intermediate.
- Fix disk space / storage atomicity so Store() cannot half-write again.
- Stop hand-editing storage objects; use Caddy's API/CLI for exports.
Defensive patterns
Strategy: validation
Validate before calling
// Pre-start: parse stored intermediate chain
if b, err := os.ReadFile(caDir + "/intermediate.crt"); err == nil {
if _, err := parseCertChainPEM(b); err != nil { fail("intermediate cert corrupt") }
} Type guard
func isParseableCertChainPEM(b []byte) bool {
rest := b
for {
var block *pem.Block
block, rest = pem.Decode(rest)
if block == nil { break }
if block.Type != "CERTIFICATE" { return false }
if _, err := x509.ParseCertificate(block.Bytes); err != nil { return false }
}
return len(rest) == 0
} Try / catch
if strings.Contains(err.Error(), "decoding intermediate certificate PEM") {
// delete intermediate cert+key only (keep root) -> Caddy regenerates under same root
} Prevention
- Treat CA storage as opaque; never edit intermediate.crt by hand.
- Verify storage integrity after restores/migrations.
- Detect and clean partial writes (file size 0 or truncated PEM footer) in pre-start checks.
When it happens
Trigger: storage.Load succeeds but the bytes fail PEM/x509 chain parsing: file truncated by a crash mid-write, a key PEM stored in intermediate.crt, base64 corruption, CRLF/BOM injected by editors or replication. Any startup/load of an existing CA with a stored intermediate.
Common situations: Partial writes from disk-full events (see the file's all-or-none TODO); operators editing or moving storage files by hand; storage replication mangling objects; backups restored incompletely.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- parsing root certificate PEM: %v
- encoding intermediate certificate: %v
- decoding root key: %v
- encoding root certificate: %v
- encoding root key: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/b3b6239e8e7c7b02.
Report an issue: GitHub.