caddyserver/caddy · error
unable to add %s to trust pool: %v
Error message
unable to add %s to trust pool: %v
What it means
Returned by ACMEIssuer.Provision (modules/caddytls/acmeissuer.go:240) when the PEM file was read successfully but x509.CertPool.AppendCertsFromPEM returned false - the content contains no parseable certificate blocks. Note the wrapped err at this point is nil (it comes from the earlier successful ReadFile), so the trailing %v prints '<nil>'; the real information is the file path itself.
Source
Thrown at modules/caddytls/acmeissuer.go:240
PropagationDelay: time.Duration(iss.Challenges.DNS.PropagationDelay),
PropagationTimeout: time.Duration(iss.Challenges.DNS.PropagationTimeout),
Resolvers: iss.Challenges.DNS.Resolvers,
OverrideDomain: iss.Challenges.DNS.OverrideDomain,
Logger: iss.logger.Named("dns_manager"),
},
}
}
// add any custom CAs to trust store
if len(iss.TrustedRootsPEMFiles) > 0 {
iss.rootPool = x509.NewCertPool()
for _, pemFile := range iss.TrustedRootsPEMFiles {
pemData, err := os.ReadFile(pemFile)
if err != nil {
return fmt.Errorf("loading trusted root CA's PEM file: %s: %v", pemFile, err)
}
if !iss.rootPool.AppendCertsFromPEM(pemData) {
return fmt.Errorf("unable to add %s to trust pool: %v", pemFile, err)
}
}
}
var err error
iss.template, err = iss.makeIssuerTemplate(ctx)
if err != nil {
return err
}
return nil
}
func (iss *ACMEIssuer) makeIssuerTemplate(ctx caddy.Context) (certmagic.ACMEIssuer, error) {
template := certmagic.ACMEIssuer{
CA: iss.CA,
TestCA: iss.TestCA,
Email: iss.Email,View on GitHub (pinned to 50e54ee279)
Solutions
- Verify the file is PEM text with certificate blocks: grep -c 'BEGIN CERTIFICATE' file (should be >=1) and openssl x509 -in file -noout
- If it is DER, convert: openssl x509 -inform DER -in file -out file.pem
- If it is a key/CSR, replace it with the CA's certificate PEM
- Re-download/restore the file and confirm its size matches the source
Example fix
# before: DER-encoded root trusted_roots /etc/caddy/roots/root-ca.der # after: convert to PEM and use it openssl x509 -inform DER -in root-ca.der -out root-ca.pem # config: trusted_roots /etc/caddy/roots/root-ca.pem
Defensive patterns
Strategy: validation
Validate before calling
# verify each trust file actually contains PEM certificates
for f in /etc/caddy/roots/*.pem; do
grep -q 'BEGIN CERTIFICATE' "$f" || { echo "$f has no PEM cert block"; exit 1; }
openssl x509 -in "$f" -noout || exit 1
done Type guard
// Go guard: file must yield at least one PEM certificate block
func hasPEMCertificates(data []byte) bool {
rest := data
for {
var block *pem.Block
block, rest = pem.Decode(rest)
if block == nil {
return false
}
if block.Type == "CERTIFICATE" {
return true
}
}
} Try / catch
if err := issuer.Provision(ctx); err != nil {
if strings.Contains(err.Error(), "unable to add") && strings.HasSuffix(err.Error(), "<nil>") {
// note: wrapped err is nil here - the file parsed but had no cert blocks;
// convert DER->PEM or replace key/CSR with the certificate
}
return err
} Prevention
- Always export CA certs as PEM (openssl x509 -outform PEM default); avoid DER for trust pools
- Grep new trust files for 'BEGIN CERTIFICATE' before referencing them
- When concatenating bundles, ensure a newline between PEM blocks
- Re-verify file sizes after transfers to catch truncation
When it happens
Trigger: The trusted-roots file contains a private key instead of a certificate, DER-encoded (binary) rather than PEM data, a chain where only the key/CSR blocks are present, or PEM with mangled headers/base64 (truncated download, Windows line-ending corruption in rare cases, or an HTML error page saved as .pem).
Common situations: Saving the wrong half of a CA pair (key instead of cert); openssl x509 -outform DER used by mistake; truncated files after failed scp/curl; concatenating files without trailing newlines between blocks; fetching from a URL that returned an error page.
Related errors
- finalizing automatic HTTPS: %v
- loading trusted root CA's PEM file: %s: %v
- parsing certificate in %s: %v
- no CERTIFICATE pem block found in %s
- encrypted private keys are not supported; please decrypt the
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/7c549c7d8c562a09.
Report an issue: GitHub.