{"record":{"id":"3a59e3bf445e50b9","repo":"temporalio/temporal","slug":"unable-to-parse-certs-as-pem","errorCode":null,"errorMessage":"unable to parse certs as PEM","messagePattern":"unable to parse certs as PEM","errorType":"validation","errorClass":"ErrTLSConfig","httpStatus":null,"severity":"error","filePath":"common/auth/tls_config_helper.go","lineNumber":158,"sourceCode":"func parseCAs(temporalTls *TLS) (*x509.CertPool, error) {\n\tvar caBytes []byte\n\tvar err error\n\tif temporalTls.CaFile != \"\" {\n\t\tcaBytes, err = os.ReadFile(temporalTls.CaFile)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: %s (%w)\", ErrTLSConfig, \"unable to read client ca file\", err)\n\t\t}\n\t} else if temporalTls.CaData != \"\" {\n\t\tcaBytes, err = base64.StdEncoding.DecodeString(temporalTls.CaData)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: %s (%w)\", ErrTLSConfig, \"unable to decode client ca data\", err)\n\t\t}\n\t}\n\tif len(caBytes) > 0 {\n\t\tcaCertPool := x509.NewCertPool()\n\t\tcaCerts, err := parseCertsFromPEM(caBytes)\n\t\tif len(caCerts) == 0 {\n\t\t\treturn nil, fmt.Errorf(\"%w: %s (%w)\", ErrTLSConfig, \"unable to parse certs as PEM\", err)\n\t\t}\n\t\tfor _, cert := range caCerts {\n\t\t\tcaCertPool.AddCert(cert)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: %s (%w)\", ErrTLSConfig, \"unable to load decoded CA Cert as PEM\", err)\n\t\t}\n\t\treturn caCertPool, nil\n\t}\n\treturn nil, nil\n}\n\nfunc parseCertsFromPEM(pemCerts []byte) ([]*x509.Certificate, error) {\n\tfor len(pemCerts) > 0 {\n\t\tvar block *pem.Block\n\t\tblock, pemCerts = pem.Decode(pemCerts)\n\t\tif block == nil {\n\t\t\tbreak","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/common/auth/tls_config_helper.go#L140-L176","documentation":"parseCAs returns this error when the CA bytes (from CaFile or decoded CaData) yield zero certificates when run through parseCertsFromPEM — i.e. the content is not a parseable PEM certificate chain. The parse error is chained and wrapped with ErrTLSConfig.","triggerScenarios":"NewTLSConfig -> parseCAs where caBytes is non-empty but contains no PEM CERTIFICATE blocks: a private key file passed as the CA, an empty/truncated file, a DER-encoded cert instead of PEM, or garbage text.","commonSituations":"Pointing caFile at the server cert's key or an unrelated file; saving a cert from a browser in DER format; a CI/CD templating step writing an empty secret; concatenating a chain without PEM headers; downloading a CA and getting an HTML error page instead of the cert.","solutions":["Open the CA file/data and confirm it starts with -----BEGIN CERTIFICATE----- and ends with -----END CERTIFICATE-----; fix the contents otherwise.","Re-export the certificate in PEM (Base64) format rather than DER.","If the file is empty, fix the secret/config delivery that was supposed to populate it.","Verify with openssl x509 -in ca.pem -noout -subject that the CA parses with OpenSSL."],"exampleFix":"// before\ntls:\n  caFile: \"/etc/temporal/certs/tls.key\"   # private key, not a CA cert\n// after\ntls:\n  caFile: \"/etc/temporal/certs/ca.pem\"    # PEM certificate chain","handlingStrategy":"validation","validationCode":"func checkCaIsPem(caBytes []byte) error {\n\tif !bytes.Contains(caBytes, []byte(\"-----BEGIN CERTIFICATE-----\")) {\n\t\treturn fmt.Errorf(\"CA data has no PEM CERTIFICATE block\")\n\t}\n\tif _, err := tls.X509KeyPair(nil, nil); false {\n\t\t_ = err\n\t}\n\tpool := x509.NewCertPool()\n\tif !pool.AppendCertsFromPEM(caBytes) {\n\t\treturn fmt.Errorf(\"no certificates parsed from CA PEM\")\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always export CA certs in PEM format, never DER","Validate files with openssl x509 -in ca.pem -noout -subject before referencing them in config","Watch for download steps that silently save HTML error pages instead of certificates","Check for empty files produced by failed secret injection before startup"],"tags":["tls","pem","config","certificates"],"backgroundTag":"invalid-pem-certificate","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}