{"record":{"id":"49630ba0944659a9","repo":"thanos-io/thanos","slug":"building-client-ca","errorCode":null,"errorMessage":"building client CA","messagePattern":"building client CA","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/tls/options.go","lineNumber":85,"sourceCode":"\t}\n\n\tmngr := &serverTLSManager{\n\t\tsrvCertPath: certPath,\n\t\tsrvKeyPath:  keyPath,\n\t\tsrvCert:     &certificate,\n\t}\n\n\ttlsCfg.GetCertificate = mngr.getCertificate\n\n\tif clientCA != \"\" {\n\t\tcaPEM, err := os.ReadFile(filepath.Clean(clientCA))\n\t\tif err != nil {\n\t\t\treturn nil, errors.Wrap(err, \"reading client CA\")\n\t\t}\n\n\t\tcertPool := x509.NewCertPool()\n\t\tif !certPool.AppendCertsFromPEM(caPEM) {\n\t\t\treturn nil, errors.Wrap(err, \"building client CA\")\n\t\t}\n\t\ttlsCfg.ClientCAs = certPool\n\t\ttlsCfg.ClientAuth = tls.RequireAndVerifyClientCert\n\n\t\tlevel.Info(logger).Log(\"msg\", \"server TLS client verification enabled\")\n\t}\n\n\treturn tlsCfg, nil\n}\n\ntype serverTLSManager struct {\n\tsrvCertPath string\n\tsrvKeyPath  string\n\n\tmtx            sync.Mutex\n\tsrvCert        *tls.Certificate\n\tsrvCertModTime time.Time\n\tsrvKeyModTime  time.Time","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/tls/options.go#L67-L103","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Verify the file contains valid PEM blocks: openssl x509 -in <cafile> -text -noout (or openssl storeutl) and fix/regenerate the file.","Convert DER to PEM if needed: openssl x509 -inform DER -in ca.crt -out ca.pem.","Ensure the mounted secret/ConfigMap actually contains the CA and was fully written (check file size, re-mount, restart pod).","Re-export the full CA chain including intermediates into the bundle."],"exampleFix":"// before\ncertPool := x509.NewCertPool()\nif !certPool.AppendCertsFromPEM(caPEM) {\n    return nil, errors.Wrap(err, \"building client CA\")\n}\n// after\ncertPool := x509.NewCertPool()\nif !certPool.AppendCertsFromPEM(caPEM) {\n    return nil, errors.New(\"building client CA: no valid PEM certificates in \" + caCert)\n}","handlingStrategy":"validation","validationCode":"func validatePEMCA(path string) error {\n    pem, err := os.ReadFile(path)\n    if err != nil { return err }\n    pool := x509.NewCertPool()\n    if !pool.AppendCertsFromPEM(pem) {\n        return fmt.Errorf(\"%s contains no valid PEM certificates\", path)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"cfg, err := tls.NewServerConfig(logger, ...)\nif err != nil && strings.Contains(err.Error(), \"building client CA\") {\n    // CA file content is invalid PEM: check/fix the file before retrying\n}","preventionTips":["Validate CA PEM files with `openssl x509 -text -noout` before deploying.","Always distribute CAs as PEM, never DER.","Verify mounted secret contents after rotation.","Check file size > 0 at startup."],"tags":["tls","x509","certificate","config"],"backgroundTag":"invalid-config-value","analyzedSha":"35b8b991177def87ed52dcf10f9b6d87f07282c8","analyzedAt":"2026-09-07T01:49:59.689Z","contentChangedAt":"2026-09-07T01:49:59.689Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}