{"record":{"id":"67e10ceecd912981","repo":"hyperledger/fabric","slug":"client-certificate-isn-t-in-pem-format-v-67e10c","errorCode":null,"errorMessage":"client certificate isn't in PEM format: %v","messagePattern":"client certificate isn't in PEM format: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/etcdraft/blockpuller.go","lineNumber":88,"sourceCode":"\t\tvb := cluster.BlockVerifierBuilder(bccsp)\n\t\treturn cluster.VerifyBlocksBFT(blocks, support.SignatureVerifier(), vb)\n\t}\n\n\tstdDialer := &cluster.StandardDialer{\n\t\tConfig: baseDialer.Config,\n\t}\n\tstdDialer.Config.AsyncConnect = false\n\tstdDialer.Config.SecOpts.VerifyCertificate = nil\n\n\t// Extract the TLS CA certs and endpoints from the configuration,\n\tendpoints, err := EndpointconfigFromSupport(support, bccsp)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tder, _ := pem.Decode(stdDialer.Config.SecOpts.Certificate)\n\tif der == nil {\n\t\treturn nil, errors.Errorf(\"client certificate isn't in PEM format: %v\",\n\t\t\tstring(stdDialer.Config.SecOpts.Certificate))\n\t}\n\n\tlogger := flogging.MustGetLogger(\"orderer.common.cluster.puller\").With(\"channel\", support.ChannelID())\n\n\tmyCert, err := x509.ParseCertificate(der.Bytes)\n\tif err != nil {\n\t\tlogger.Warnf(\"Failed parsing my own TLS certificate: %v, therefore we may connect to our own endpoint when pulling blocks\", err)\n\t}\n\n\tbp := &cluster.BlockPuller{\n\t\tMyOwnTLSCert:        myCert,\n\t\tVerifyBlockSequence: verifyBlockSequence,\n\t\tLogger:              logger,\n\t\tRetryTimeout:        clusterConfig.ReplicationRetryTimeout,\n\t\tMaxTotalBufferBytes: clusterConfig.ReplicationBufferSize,\n\t\tFetchTimeout:        clusterConfig.ReplicationPullTimeout,\n\t\tEndpoints:           endpoints,","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/etcdraft/blockpuller.go#L70-L106","documentation":"NewBlockPuller validates the orderer's own TLS client certificate before building the cluster block puller. The certificate bytes in the dialer's SecOpts.Certificate must be PEM-encoded; if pem.Decode fails, the configured certificate is malformed and the puller cannot be created. The raw bytes are included in the error to aid diagnosis.","triggerScenarios":"Starting an etcdraft chain (NewBlockPuller via EndpointconfigFromSupport flow) when generalTLS or cluster TLS client certificate material in configuration (General.TLS.Certificate / General.Cluster.ClientCertificate) is not valid PEM — e.g., raw DER bytes, base64-only content, or an empty/garbled file.","commonSituations":"Config map/env var corruption where newlines in the PEM got mangled (e.g., single-line env values), pasting a certificate without the BEGIN/END headers, or generating a cert and forgetting PEM encoding.","solutions":["Verify General.TLS.Certificate (and General.Cluster.ClientCertificate) point to a valid PEM file beginning with '-----BEGIN CERTIFICATE-----'.","Re-encode: openssl x509 -in cert.crt -out cert.pem and redeploy the orderer with the corrected file.","If injecting via env/Kubernetes config, ensure newlines are preserved (use | multiline YAML or proper file mounts, not flattened env values).","Confirm the private key (TLS.PrivateKey) and cert are a matching pair with openssl x509 / openssl rsa modulus comparison."],"exampleFix":"// before: DER or header-less cert loaded\nSecOpts.Certificate = rawDerBytes\n\n// after: proper PEM-encoded certificate\npemBytes, _ := os.ReadFile(\"orderer.crt\") // starts with -----BEGIN CERTIFICATE-----\nSecOpts.Certificate = pemBytes","handlingStrategy":"validation","validationCode":"func isPEMCert(b []byte) bool {\n    block, _ := pem.Decode(b)\n    if block == nil || block.Type != \"CERTIFICATE\" {\n        return false\n    }\n    _, err := x509.ParseCertificate(block.Bytes)\n    return err == nil\n}\n// call before building SecOpts: if !isPEMCert(certBytes) { fail fast }","typeGuard":"func validPEMCertificate(data []byte) bool {\n    der, _ := pem.Decode(data)\n    return der != nil\n}","tryCatchPattern":null,"preventionTips":["Mount TLS certs as files, never inline through env vars that strip newlines","Validate PEMs at deploy time: openssl x509 -in cert.pem -noout","Keep BEGIN/END headers intact in config maps"],"tags":["orderer","tls","certificate","etcdraft"],"backgroundTag":"certificate-not-pem-encoded","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}