thanos-io/thanos · error

building client CA

Error message

building client CA

What it means

NewServerConfig wraps this error when the server's client-CA PEM file was read successfully but its certificates could not be parsed into an x509.CertPool via AppendCertsFromPEM, which returns false on any malformed/unparseable PEM data. It means the CA file exists but does not contain valid PEM-encoded certificates. The wrap also has a latent bug: it wraps the outer err (nil at that point) instead of a descriptive cause.

Solutions

  1. Verify the file contains valid PEM blocks: openssl x509 -in <cafile> -text -noout (or openssl storeutl) and fix/regenerate the file.
  2. Convert DER to PEM if needed: openssl x509 -inform DER -in ca.crt -out ca.pem.
  3. Ensure the mounted secret/ConfigMap actually contains the CA and was fully written (check file size, re-mount, restart pod).
  4. Re-export the full CA chain including intermediates into the bundle.

Example fix

// before
certPool := x509.NewCertPool()
if !certPool.AppendCertsFromPEM(caPEM) {
    return nil, errors.Wrap(err, "building client CA")
}
// after
certPool := x509.NewCertPool()
if !certPool.AppendCertsFromPEM(caPEM) {
    return nil, errors.New("building client CA: no valid PEM certificates in " + caCert)
}
Defensive patterns

Strategy: validation

Validate before calling

func validatePEMCA(path string) error {
    pem, err := os.ReadFile(path)
    if err != nil { return err }
    pool := x509.NewCertPool()
    if !pool.AppendCertsFromPEM(pem) {
        return fmt.Errorf("%s contains no valid PEM certificates", path)
    }
    return nil
}

Try / catch

cfg, err := tls.NewServerConfig(logger, ...)
if err != nil && strings.Contains(err.Error(), "building client CA") {
    // CA file content is invalid PEM: check/fix the file before retrying
}

Prevention

When it happens

Trigger: NewServerConfig(..., clientCAPath, ...) is called with a caCert file whose contents are not valid PEM certificate blocks (e.g. empty file, DER-encoded cert, private key, concatenated garbage, or a truncated download).

Common situations: Pointing --client-ca-file at a DER .crt instead of PEM; a secret/ConfigMap mounted empty or truncated; a file containing only a private key or CSR; copy-paste corruption of a CA bundle; a renewal process writing partial content mid-read.

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


AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07). Data as JSON: /api/errors/49630ba0944659a9. Report an issue: GitHub.

Appendix: source

Thrown at pkg/tls/options.go:85

	}

	mngr := &serverTLSManager{
		srvCertPath: certPath,
		srvKeyPath:  keyPath,
		srvCert:     &certificate,
	}

	tlsCfg.GetCertificate = mngr.getCertificate

	if clientCA != "" {
		caPEM, err := os.ReadFile(filepath.Clean(clientCA))
		if err != nil {
			return nil, errors.Wrap(err, "reading client CA")
		}

		certPool := x509.NewCertPool()
		if !certPool.AppendCertsFromPEM(caPEM) {
			return nil, errors.Wrap(err, "building client CA")
		}
		tlsCfg.ClientCAs = certPool
		tlsCfg.ClientAuth = tls.RequireAndVerifyClientCert

		level.Info(logger).Log("msg", "server TLS client verification enabled")
	}

	return tlsCfg, nil
}

type serverTLSManager struct {
	srvCertPath string
	srvKeyPath  string

	mtx            sync.Mutex
	srvCert        *tls.Certificate
	srvCertModTime time.Time
	srvKeyModTime  time.Time

View on GitHub (pinned to 35b8b99117)