temporalio/temporal · error
failed to decode PEM certificate data
Error message
failed to decode PEM certificate data
What it means
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.
Source
Thrown at common/rpc/encryption/local_store_cert_provider.go:484
}
// logic borrowed from tls.X509KeyPair()
func parseCert(bytes []byte) (*x509.Certificate, error) {
var certBytes [][]byte
for {
var certDERBlock *pem.Block
certDERBlock, bytes = pem.Decode(bytes)
if certDERBlock == nil {
break
}
if certDERBlock.Type == "CERTIFICATE" {
certBytes = append(certBytes, certDERBlock.Bytes)
}
}
if len(certBytes) == 0 || len(certBytes[0]) == 0 {
return nil, fmt.Errorf("failed to decode PEM certificate data")
}
return x509.ParseCertificate(certBytes[0])
}
func appendError(aggregatedErr error, err error) error {
if aggregatedErr == nil {
return err
}
if err == nil {
return aggregatedErr
}
return fmt.Errorf("%v, %w", aggregatedErr, err)
}
func (s *localStoreCertProvider) refreshCerts() {
for {
select {View on GitHub (pinned to bde624efd1)
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.
Example fix
// before certData := "MIIDczCCA..." // raw DER base64, no PEM armor // after pemData := "-----BEGIN CERTIFICATE-----\n" + certData + "\n-----END CERTIFICATE-----"
Defensive patterns
Strategy: validation
Validate before calling
func hasPEMCert(data []byte) bool {
for block, rest := pem.Decode(data); block != nil; block, rest = pem.Decode(rest) {
if block.Type == "CERTIFICATE" && len(block.Bytes) > 0 {
return true
}
}
return false
} Type guard
if data == nil || len(data) == 0 || !hasPEMCert(data) { return errors.New("no PEM CERTIFICATE block found") } Try / catch
if _, err := parseCert(data); err != nil {
if strings.Contains(err.Error(), "failed to decode PEM certificate data") {
// fall back to an alternate cert source or fail fast with a clear config error
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to load decoded CA Cert as PEM
- unable to parse certs as PEM
- unable to load decoded CA Cert as PEM
- loading server tls certificate failed: %v
- URI is invalid
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/b166bb9187aef904.
Report an issue: GitHub.