{"record":{"id":"7c549c7d8c562a09","repo":"caddyserver/caddy","slug":"unable-to-add-s-to-trust-pool-v","errorCode":null,"errorMessage":"unable to add %s to trust pool: %v","messagePattern":"unable to add (.+?) to trust pool: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/acmeissuer.go","lineNumber":240,"sourceCode":"\t\t\t\tPropagationDelay:   time.Duration(iss.Challenges.DNS.PropagationDelay),\n\t\t\t\tPropagationTimeout: time.Duration(iss.Challenges.DNS.PropagationTimeout),\n\t\t\t\tResolvers:          iss.Challenges.DNS.Resolvers,\n\t\t\t\tOverrideDomain:     iss.Challenges.DNS.OverrideDomain,\n\t\t\t\tLogger:             iss.logger.Named(\"dns_manager\"),\n\t\t\t},\n\t\t}\n\t}\n\n\t// add any custom CAs to trust store\n\tif len(iss.TrustedRootsPEMFiles) > 0 {\n\t\tiss.rootPool = x509.NewCertPool()\n\t\tfor _, pemFile := range iss.TrustedRootsPEMFiles {\n\t\t\tpemData, err := os.ReadFile(pemFile)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"loading trusted root CA's PEM file: %s: %v\", pemFile, err)\n\t\t\t}\n\t\t\tif !iss.rootPool.AppendCertsFromPEM(pemData) {\n\t\t\t\treturn fmt.Errorf(\"unable to add %s to trust pool: %v\", pemFile, err)\n\t\t\t}\n\t\t}\n\t}\n\n\tvar err error\n\tiss.template, err = iss.makeIssuerTemplate(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (iss *ACMEIssuer) makeIssuerTemplate(ctx caddy.Context) (certmagic.ACMEIssuer, error) {\n\ttemplate := certmagic.ACMEIssuer{\n\t\tCA:                iss.CA,\n\t\tTestCA:            iss.TestCA,\n\t\tEmail:             iss.Email,","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/acmeissuer.go#L222-L258","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"# before: DER-encoded root\n trusted_roots /etc/caddy/roots/root-ca.der\n\n# after: convert to PEM and use it\nopenssl x509 -inform DER -in root-ca.der -out root-ca.pem\n# config:\n trusted_roots /etc/caddy/roots/root-ca.pem","handlingStrategy":"validation","validationCode":"# verify each trust file actually contains PEM certificates\nfor f in /etc/caddy/roots/*.pem; do\n  grep -q 'BEGIN CERTIFICATE' \"$f\" || { echo \"$f has no PEM cert block\"; exit 1; }\n  openssl x509 -in \"$f\" -noout || exit 1\ndone","typeGuard":"// Go guard: file must yield at least one PEM certificate block\nfunc hasPEMCertificates(data []byte) bool {\n\trest := data\n\tfor {\n\t\tvar block *pem.Block\n\t\tblock, rest = pem.Decode(rest)\n\t\tif block == nil {\n\t\t\treturn false\n\t\t}\n\t\tif block.Type == \"CERTIFICATE\" {\n\t\t\treturn true\n\t\t}\n\t}\n}","tryCatchPattern":"if err := issuer.Provision(ctx); err != nil {\n    if strings.Contains(err.Error(), \"unable to add\") && strings.HasSuffix(err.Error(), \"<nil>\") {\n        // note: wrapped err is nil here - the file parsed but had no cert blocks;\n        // convert DER->PEM or replace key/CSR with the certificate\n    }\n    return err\n}","preventionTips":["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"],"tags":["tls","acme","trust-store","pem","certificates"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}