{"record":{"id":"b166bb9187aef904","repo":"temporalio/temporal","slug":"failed-to-decode-pem-certificate-data","errorCode":null,"errorMessage":"failed to decode PEM certificate data","messagePattern":"failed to decode PEM certificate data","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/rpc/encryption/local_store_cert_provider.go","lineNumber":484,"sourceCode":"}\n\n// logic borrowed from tls.X509KeyPair()\nfunc parseCert(bytes []byte) (*x509.Certificate, error) {\n\n\tvar certBytes [][]byte\n\tfor {\n\t\tvar certDERBlock *pem.Block\n\t\tcertDERBlock, bytes = pem.Decode(bytes)\n\t\tif certDERBlock == nil {\n\t\t\tbreak\n\t\t}\n\t\tif certDERBlock.Type == \"CERTIFICATE\" {\n\t\t\tcertBytes = append(certBytes, certDERBlock.Bytes)\n\t\t}\n\t}\n\n\tif len(certBytes) == 0 || len(certBytes[0]) == 0 {\n\t\treturn nil, fmt.Errorf(\"failed to decode PEM certificate data\")\n\t}\n\treturn x509.ParseCertificate(certBytes[0])\n}\n\nfunc appendError(aggregatedErr error, err error) error {\n\tif aggregatedErr == nil {\n\t\treturn err\n\t}\n\tif err == nil {\n\t\treturn aggregatedErr\n\t}\n\treturn fmt.Errorf(\"%v, %w\", aggregatedErr, err)\n}\n\nfunc (s *localStoreCertProvider) refreshCerts() {\n\n\tfor {\n\t\tselect {","sourceCodeStart":466,"sourceCodeEnd":502,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/common/rpc/encryption/local_store_cert_provider.go#L466-L502","documentation":"parseCert decodes PEM blocks from a cert file/data and builds an x509.Certificate. After iterating all PEM blocks, if no CERTIFICATE-typed block yielded non-empty DER bytes, it returns \"failed to decode PEM certificate data\". This means the input contained no usable certificate, though some parsing may have partially succeeded. It guards x509.ParseCertificate from being called with empty input.","triggerScenarios":"Calling parseCert (via buildCAPool or FetchServerCertificate/FetchClientCAs in localStoreCertProvider) with PEM data that contains zero CERTIFICATE blocks — e.g. only PRIVATE KEY blocks, garbage text, an empty file, or base64 blob passed where PEM is expected.","commonSituations":"Mounting a Kubernetes secret with the wrong key (tls.key instead of tls.crt); an empty cert file on disk after a failed secret sync; passing raw DER bytes instead of PEM-encoded text; a config pointing at a configmap key that holds a private key rather than a certificate.","solutions":["Verify the referenced file/data actually contains a PEM block starting with '-----BEGIN CERTIFICATE-----'.","Check you did not swap cert and key paths/data in configuration (key passed where cert expected).","Re-export or re-create the certificate; confirm it is non-empty and PEM-encoded (openssl x509 -in cert.pem -text).","If you have raw DER bytes, wrap them with encoding/pem before passing them in."],"exampleFix":"// before\ncertData := \"MIIDczCCA...\" // raw DER base64, no PEM armor\n// after\npemData := \"-----BEGIN CERTIFICATE-----\\n\" + certData + \"\\n-----END CERTIFICATE-----\"","handlingStrategy":"validation","validationCode":"func hasPEMCert(data []byte) bool {\n    for block, rest := pem.Decode(data); block != nil; block, rest = pem.Decode(rest) {\n        if block.Type == \"CERTIFICATE\" && len(block.Bytes) > 0 {\n            return true\n        }\n    }\n    return false\n}","typeGuard":"if data == nil || len(data) == 0 || !hasPEMCert(data) { return errors.New(\"no PEM CERTIFICATE block found\") }","tryCatchPattern":"if _, err := parseCert(data); err != nil {\n    if strings.Contains(err.Error(), \"failed to decode PEM certificate data\") {\n        // fall back to an alternate cert source or fail fast with a clear config error\n    }\n}","preventionTips":["Verify cert files with openssl x509 before deploying.","Never pass private keys or raw DER where PEM certificates are expected.","Add a startup readiness check that PEM files are non-empty."],"tags":["tls","x509","pem","certificate"],"backgroundTag":"invalid-pem-certificate","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}