{"record":{"id":"3c1f9433a980fdfd","repo":"temporalio/temporal","slug":"unable-to-decode-client-certificate","errorCode":null,"errorMessage":"unable to decode client certificate","messagePattern":"unable to decode client certificate","errorType":"validation","errorClass":"ErrTLSConfig","httpStatus":null,"severity":"error","filePath":"common/auth/tls_config_helper.go","lineNumber":200,"sourceCode":"\t\tcertBytes := block.Bytes\n\t\treturn x509.ParseCertificates(certBytes)\n\t}\n\treturn nil, nil\n}\n\nfunc parseClientCert(temporalTls *TLS) (*tls.Certificate, error) {\n\tvar certBytes []byte\n\tvar keyBytes []byte\n\tvar err error\n\tif temporalTls.CertFile != \"\" {\n\t\tcertBytes, err = os.ReadFile(temporalTls.CertFile)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: %s (%w)\", ErrTLSConfig, \"unable to read client certificate file\", err)\n\t\t}\n\t} else if temporalTls.CertData != \"\" {\n\t\tcertBytes, err = base64.StdEncoding.DecodeString(temporalTls.CertData)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: %s (%w)\", ErrTLSConfig, \"unable to decode client certificate\", err)\n\t\t}\n\t}\n\n\tif temporalTls.KeyFile != \"\" {\n\t\tkeyBytes, err = os.ReadFile(temporalTls.KeyFile)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: %s (%w)\", ErrTLSConfig, \"unable to read client certificate private key file\", err)\n\t\t}\n\t} else if temporalTls.KeyData != \"\" {\n\t\tkeyBytes, err = base64.StdEncoding.DecodeString(temporalTls.KeyData)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: %s (%w)\", ErrTLSConfig, \"unable to decode client certificate private key\", err)\n\t\t}\n\t}\n\n\tif len(certBytes) > 0 {\n\t\tclientCert, err := tls.X509KeyPair(certBytes, keyBytes)\n\t\tif err != nil {","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/common/auth/tls_config_helper.go#L182-L218","documentation":"parseClientCert returns this error when CertData is set but base64.StdEncoding.DecodeString fails — the value is not valid base64. The decode error is chained and wrapped with ErrTLSConfig so the caller knows their inline client certificate is malformed before any TLS handshake occurs.","triggerScenarios":"NewTLSConfig -> parseClientCert with CertData containing raw PEM text, truncated base64, or a string corrupted by whitespace/newlines/escaping during config templating.","commonSituations":"Pasting the PEM cert directly instead of base64-encoding it; kubectl/secret tooling that already wrapped or altered the base64; YAML multiline strings inserting newlines into the value; double-encoding leaving invalid characters.","solutions":["Regenerate the value with base64 -w0 client.pem and paste that exact single-line string into CertData.","Confirm it decodes once to PEM text starting with -----BEGIN CERTIFICATE----- (not base64 of base64).","Remove newlines/whitespace introduced by YAML block scalars or templating; use a folded/single-line string.","Switch to CertFile to avoid inline encoding issues entirely."],"exampleFix":"// before\ntls:\n  certData: \"-----BEGIN CERTIFICATE-----\\nMIID...\"   # raw PEM\n// after\ntls:\n  certData: \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQ...\" # base64 -w0 client.pem","handlingStrategy":"validation","validationCode":"func checkCertDataIsBase64(certData string) error {\n\tdecoded, err := base64.StdEncoding.DecodeString(certData)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"certData is not valid base64: %w\", err)\n\t}\n\tif !strings.Contains(string(decoded), \"BEGIN CERTIFICATE\") {\n\t\treturn fmt.Errorf(\"certData does not decode to PEM certificate\")\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Encode inline certs with base64 -w0 client.pem and store as a single-line string","Avoid YAML block scalars for base64 values, or strip inserted newlines","Verify locally before deploy: echo '<value>' | base64 -d | openssl x509 -noout -subject","Prefer certFile mounts over inline data when the format fights you"],"tags":["tls","config","encoding","base64","mtls"],"backgroundTag":"invalid-base64","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}