{"record":{"id":"2c8987000a12d5d9","repo":"hyperledger/fabric","slug":"client-certificate-isn-t-in-pem-format-v","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/common/follower/block_puller.go","lineNumber":74,"sourceCode":"// NewBlockPullerCreator creates a new BlockPullerCreator, using the configuration details that do not change during\n// the life cycle of the orderer.\nfunc NewBlockPullerCreator(\n\tchannelID string,\n\tlogger *flogging.FabricLogger,\n\tsigner identity.SignerSerializer,\n\tbaseDialer *cluster.PredicateDialer,\n\tclusterConfig localconfig.Cluster,\n\tbccsp bccsp.BCCSP,\n) (*BlockPullerCreator, error) {\n\tstdDialer := &cluster.StandardDialer{\n\t\tConfig: baseDialer.Config,\n\t}\n\tstdDialer.Config.AsyncConnect = false\n\tstdDialer.Config.SecOpts.VerifyCertificate = nil\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\tfactory := &BlockPullerCreator{\n\t\tchannelID: channelID,\n\t\tbccsp:     bccsp,\n\t\tblockSigVerifierFactory: &deliverclient.BlockVerifierAssembler{\n\t\t\tLogger: logger,\n\t\t\tBCCSP:  bccsp,\n\t\t},\n\t\tclusterConfig:       clusterConfig,\n\t\tsigner:              signer,\n\t\tstdDialer:           stdDialer,\n\t\tder:                 der,\n\t\tClusterVerifyBlocks: cluster.VerifyBlocksBFT, // The default block sequence verification method.\n\t\tvb:                  cluster.BlockVerifierBuilder(bccsp),\n\t}\n","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/follower/block_puller.go#L56-L92","documentation":"NewBlockPullerCreator decodes the configured client TLS certificate with pem.Decode; if no PEM block can be parsed it wraps the failure with the raw certificate bytes. This means the SecOpts.Certificate is not PEM-encoded, so the TLS material is unusable for the block puller's gRPC client.","triggerScenarios":"Creating a follower's BlockPullerCreator (via createFollower or the anonymous init path) when tls.ClientCert (or the equivalent general config) points to a file whose bytes are not PEM (DER-encoded binary, empty file, HTML error page, wrong file).","commonSituations":"Configured certificate path actually contains the private key or a DER .cer file; file fetched by mistake (404 page); cert concatenated with garbage; Fabric version/config migration left tls paths pointing at wrong files.","solutions":["Point the TLS client certificate config to a valid PEM file beginning with '-----BEGIN CERTIFICATE-----'","Verify the file content with `openssl x509 -in cert.pem -text -noout`; if it fails, re-export in PEM (`openssl x509 -inform DER -in cert.der -out cert.pem`)","Re-generate the certificate from the MSP (e.g. copy signcerts/cert.pem from the organization's MSP directory)","Check the crypto material wasn't truncated or replaced during channel join setup"],"exampleFix":"// before (yaml)\ntls:\n  clientKey:\n    file: /path/to/client.cer   # DER binary\n  clientCert:\n    file: /path/to/client.cer\n// after\ntls:\n  clientKey:\n    file: /path/to/client.key\n  clientCert:\n    file: /path/to/client-cert.pem  # '-----BEGIN CERTIFICATE-----'","handlingStrategy":"validation","validationCode":"certPEM, err := os.ReadFile(cfg.TLS.ClientCertFile)\nif err != nil {\n    return fmt.Errorf(\"cannot read client cert: %w\", err)\n}\nblock, _ := pem.Decode(certPEM)\nif block == nil || block.Type != \"CERTIFICATE\" {\n    return fmt.Errorf(\"client cert %s is not PEM-encoded\", cfg.TLS.ClientCertFile)\n}\nif _, err := x509.ParseCertificate(block.Bytes); err != nil {\n    return fmt.Errorf(\"client cert is not a valid certificate: %w\", err)\n}","typeGuard":"func isPEMCertificate(data []byte) bool {\n    block, _ := pem.Decode(data)\n    return block != nil && block.Type == \"CERTIFICATE\"\n}","tryCatchPattern":"creator, err := blockpuller.NewBlockPullerCreator(...)\nif err != nil {\n    if strings.Contains(err.Error(), \"client certificate isn't in PEM format\") {\n        return fmt.Errorf(\"TLS client certificate invalid; re-export PEM from MSP: %w\", err)\n    }\n    return err\n}","preventionTips":["Point clientCert config at the signcerts/cert.pem of the client MSP, never at a DER/.cer file","Validate cert files with `openssl x509 -in <file> -noout` before deploying","Keep key and cert files distinct and correctly named","Re-copy crypto material after any MSP regeneration"],"tags":["tls","pem","configuration"],"backgroundTag":"certificate-not-pem","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"}