caddyserver/caddy · error
parsing certificate at index %d: %v
Error message
parsing certificate at index %d: %v
What it means
InlineCAPool.Provision decodes each entry of trusted_ca_certs (base64-encoded DER certificates) with decodeBase64DERCert. When an entry is not valid base64, not DER, or not an X.509 certificate, provisioning of the client CA pool fails, reporting the failing index so you can locate the bad entry.
Source
Thrown at modules/caddytls/capools.go:77
// CaddyModule implements caddy.Module.
func (icp InlineCAPool) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "tls.ca_pool.source.inline",
New: func() caddy.Module {
return new(InlineCAPool)
},
}
}
// Provision implements caddy.Provisioner.
func (icp *InlineCAPool) Provision(ctx caddy.Context) error {
caPool := x509.NewCertPool()
var certs []*x509.Certificate
for i, clientCAString := range icp.TrustedCACerts {
clientCA, err := decodeBase64DERCert(clientCAString)
if err != nil {
return fmt.Errorf("parsing certificate at index %d: %v", i, err)
}
caPool.AddCert(clientCA)
certs = append(certs, clientCA)
}
icp.pool = caPool
icp.certs = certs
return nil
}
// Syntax:
//
// trust_pool inline {
// trust_der <base64_der_cert>...
// }
//
// The 'trust_der' directive can be specified multiple times.
func (icp *InlineCAPool) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {View on GitHub (pinned to 50e54ee279)
Solutions
- Convert the PEM to base64 DER: openssl x509 -in ca.pem -outform der | base64 -w0, then use that string.
- Check the reported index against your trusted_ca_certs array to find the exact bad entry.
- Alternatively use trusted_ca_certs_pem_files (PEM file path) which avoids the conversion entirely.
- Verify the string is a single unbroken standard-alphabet base64 blob with no stray characters.
Example fix
# before (PEM text stuffed into the base64-DER field) "trusted_ca_certs": ["-----BEGIN CERTIFICATE-----\nMIIF..."] # after (base64 DER) openssl x509 -in ca.pem -outform der | base64 -w0 "trusted_ca_certs": ["MIIFazCCA...="]
Defensive patterns
Strategy: validation
Validate before calling
// Pre-check each inline cert exactly as Caddy does.
for i, s := range poolCfg.TrustedCACerts {
if _, err := decodeBase64DERCert(s); err != nil { // or inline: base64 decode + x509.ParseCertificate
return fmt.Errorf("trusted_ca_certs[%d] invalid: %v", i, err)
}
} Type guard
func isBase64DERCert(s string) bool {
der, err := base64.StdEncoding.DecodeString(strings.TrimSpace(s))
if err != nil {
return false
}
_, err = x509.ParseCertificate(der)
return err == nil
} Prevention
- Generate the value with openssl x509 -outform der | base64 -w0, never paste PEM text.
- Automate cert-bundle generation in config pipelines so hand-conversion errors cannot occur.
- Prefer PEM file references when hand-editing configs.
When it happens
Trigger: Configuring client_auth.trusted_ca_certs (or the Caddyfile trusted_ca_cert_file's inline sibling) with a value that is a PEM string instead of base64 DER, has trailing whitespace/newline corruption, uses URL-safe instead of standard base64, or is a truncated copy-paste.
Common situations: Copy-pasting a PEM block (-----BEGIN CERTIFICATE-----) into a field that expects bare base64 DER; line-wrapped base64 pasted with literal '\n' characters; using the certificate's fingerprint instead of the certificate.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- access control %d public key %d: parsing base64 certificate
- loading external certificate manager modules: %v
- reading %s: %v
- parsing certificate in %s: %v
- URL is required
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/2d8ca0182f128099.
Report an issue: GitHub.