t8y2/dbx · error

failed to parse CA certificate at %s

Error message

failed to parse CA certificate at %s

What it means

tlsConfigFor builds a TLS configuration for the etcd client connection. When a CA certificate file is specified, it reads the PEM file and attempts to append its certificates to an x509 CertPool; if AppendCertsFromPEM fails, no usable certificates were found in the file and the library aborts with this error rather than silently building an insecure/empty trust store.

Source

Thrown at agents/drivers/etcd-go/client.go:282

		value, err := strconv.Atoi(entry[separator+1:])
		if err != nil {
			return fallback
		}
		return value
	}
	return fallback
}

func tlsConfigFor(connection connectionParams) (*tls.Config, error) {
	tlsConfig := &tls.Config{}
	if ca := strings.TrimSpace(connection.CACertPath); ca != "" {
		authorityPEM, err := os.ReadFile(ca)
		if err != nil {
			return nil, err
		}
		pool := x509.NewCertPool()
		if !pool.AppendCertsFromPEM(authorityPEM) {
			return nil, fmt.Errorf("failed to parse CA certificate at %s", ca)
		}
		tlsConfig.RootCAs = pool
	}
	certPath := firstNonBlank(connection.ClientCertPath, connection.CertPath)
	keyPath := firstNonBlank(connection.ClientKeyPath, connection.KeyPath)
	if (certPath == "") != (keyPath == "") {
		return nil, errors.New("Client certificate and key must be provided together")
	}
	if certPath != "" {
		pair, err := tls.LoadX509KeyPair(certPath, keyPath)
		if err != nil {
			return nil, err
		}
		if len(pair.Certificate) > 0 {
			pair.Leaf, err = x509.ParseCertificate(pair.Certificate[0])
			if err != nil {
				return nil, err
			}

View on GitHub (pinned to c0390bff16)

Solutions

  1. Verify the file at the CA path contains a PEM block starting with '-----BEGIN CERTIFICATE-----'; open it and check the first line.
  2. If the file is DER-encoded, convert it: openssl x509 -inform DER -in ca.crt -out ca.pem.
  3. Ensure you are pointing at the CA/issuer bundle, not the server or client certificate; re-export from your PKI or cluster (e.g. kubectl get secret ... -o jsonpath='{.data.ca\.crt}' | base64 -d).
  4. Check the file is not empty or truncated (ls -l, compare byte size with source); re-copy in binary mode.
  5. Confirm the code reads the correct path: CAPath vs ClientCertPath mix-ups resolve via firstNonBlank; fix the connection config field.

Example fix

// before
connection.CAPath = "/etc/pki/server.crt" // DER-encoded, AppendCertsFromPEM fails
// after
// convert to PEM first: openssl x509 -inform DER -in server.crt -out ca.pem
connection.CAPath = "/etc/pki/ca.pem"
Defensive patterns

Strategy: validation

Validate before calling

func caFileLooksValid(path string) error {
	b, err := os.ReadFile(path)
	if err != nil {
		return err
	}
	if !bytes.Contains(b, []byte("-----BEGIN CERTIFICATE-----")) {
		return fmt.Errorf("%s contains no PEM certificate block", path)
	}
	if !x509.NewCertPool().AppendCertsFromPEM(b) {
		return fmt.Errorf("%s has no parseable certificates", path)
	}
	return nil
}
// call caFileLooksValid(connection.CAPath) before buildClient

Type guard

func isPEMCert(data []byte) bool {
	block, _ := pem.Decode(data)
	return block != nil && block.Type == "CERTIFICATE"
}

Prevention

When it happens

Trigger: tlsConfigFor is called (via buildClient) with connection.CAPath set to a file that exists and is readable, but whose bytes contain no parseable PEM certificate blocks (e.g. empty file, a private key, a chain of intermediates only, DER-encoded cert, or HTML error page).

Common situations: Pointing CAPath at a server cert instead of the CA bundle; copying a certificate through a tool that mangled it (e.g. text-mode transfer, truncated file); using a DER .crt file where PEM is required; passing a Kubernetes secret key that is empty or contains a key rather than a cert; stale mount/secret after rotation leaving a zero-byte file.

Understand the failure class

Related errors


AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/bb5f4e5c6d0930fa. Report an issue: GitHub.