cloudflare/cloudflared · error
error appending custom CA to cert pool
Error message
error appending custom CA to cert pool
What it means
LoadCustomOriginCA reads a user-supplied CA PEM file (via --origin-ca-pool) and adds it to an x509 CertPool. If crypto/x509's AppendCertsFromPEM returns false — the file parsed to zero valid PEM certificates — cloudflared returns this error because the origin CA pool would otherwise silently trust nothing, breaking origin TLS validation.
Source
Thrown at tlsconfig/origin_ca.go:71
if err != nil {
return nil, errors.Wrap(err, "could not append Cloudflare Root CAs to cloudflared certificate pool")
}
for _, cert := range cfRootCA {
certPool.AddCert(cert)
}
if originCAFilename == "" {
return certPool, nil
}
// nolint: gosec
customOriginCA, err := os.ReadFile(originCAFilename)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("unable to read the file %s", originCAFilename))
}
if !certPool.AppendCertsFromPEM(customOriginCA) {
return nil, fmt.Errorf("error appending custom CA to cert pool")
}
return certPool, nil
}
func CreateTunnelConfig(caCert string, serverName string) (*tls.Config, error) {
tlsConfig := &tls.Config{ServerName: serverName}
if caCert != "" {
caCertPEM, err := os.ReadFile(caCert) //nolint:gosec
if err != nil {
return nil, fmt.Errorf("read CA certificate %s: %w", caCert, err)
}
rootCAPool := x509.NewCertPool()
if !rootCAPool.AppendCertsFromPEM(caCertPEM) {
return nil, fmt.Errorf("parse CA certificate %s", caCert)
}
tlsConfig.RootCAs = rootCAPool
}View on GitHub (pinned to 2253eeeb25)
Solutions
- Convert the certificate to PEM format: `openssl x509 -inform DER -in ca.der -out ca.pem` and pass the PEM file.
- Verify the file actually contains certificates: `openssl x509 -in ca.pem -noout -subject` should print a subject.
- Check you are not passing a private key or CSR file; the pool needs CA certificates.
- Confirm the path via --origin-ca-pool is correct and the file is non-empty (`ls -l`, `head -1` should show -----BEGIN CERTIFICATE-----).
- Concatenate intermediate + root CAs into one PEM bundle if the chain is split across files.
Example fix
// before (DER file passed directly) originServerName: "example.com" originCA: "/etc/ssl/certs/ca.der" // after (converted to PEM) # openssl x509 -inform DER -in /etc/ssl/certs/ca.der -out /etc/ssl/certs/ca.pem originServerName: "example.com" originCA: "/etc/ssl/certs/ca.pem"
Defensive patterns
Strategy: validation
Validate before calling
// guard before invoking the flag path
pemBytes, err := os.ReadFile(caPath)
if err != nil {
return err
}
if !bytes.Contains(pemBytes, []byte("-----BEGIN CERTIFICATE-----")) {
return fmt.Errorf("%s is not a PEM certificate bundle", caPath)
}
block, _ := pem.Decode(pemBytes)
if block == nil || block.Type != "CERTIFICATE" {
return fmt.Errorf("%s has no PEM CERTIFICATE block", caPath)
}
if _, err := x509.ParseCertificate(block.Bytes); err != nil {
return fmt.Errorf("%s contains an unparseable certificate: %v", caPath, err)
} Type guard
func isPEMCertBundle(data []byte) bool {
block, _ := pem.Decode(data)
return block != nil && block.Type == "CERTIFICATE"
} Try / catch
pool, err := tlsconfig.LoadCustomOriginCA(caPath)
if err != nil {
if strings.Contains(err.Error(), "appending custom CA") {
return fmt.Errorf("CA pool file %s is not valid PEM: %w", caPath, err)
}
return err
} Prevention
- Always supply PEM (BEGIN CERTIFICATE) files to --origin-ca-pool; convert DER with openssl.
- Verify the file with `openssl x509 -in ca.pem -noout -subject` before deploying.
- Include full chain (root + intermediates) in the bundle; never point the flag at private keys.
When it happens
Trigger: --origin-ca-pool points to a file whose content is not PEM (DER-encoded cert, private key, HTML error page, empty file), contains certificates in an unsupported format, or the file read succeeded but every PEM block failed to parse as a certificate.
Common situations: Exporting a cert from a browser/Windows store as DER instead of PEM; pointing the flag at a private key or bundle of CSRs; config copied from docs with a placeholder path; a proxy download saving an HTML login page as ca.pem.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- parse CA certificate %s
- read CA certificate %s: %w
- either ServerName or InsecureSkipVerify must be specified in
- unable to create TLS config to connect with edge
- Error loading cert pool
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/ff658a82c9f40f45.
Report an issue: GitHub.