hyperledger/fabric · error
client certificate isn't in PEM format: %v
Error message
client certificate isn't in PEM format: %v
What it means
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.
Source
Thrown at orderer/common/follower/block_puller.go:74
// NewBlockPullerCreator creates a new BlockPullerCreator, using the configuration details that do not change during
// the life cycle of the orderer.
func NewBlockPullerCreator(
channelID string,
logger *flogging.FabricLogger,
signer identity.SignerSerializer,
baseDialer *cluster.PredicateDialer,
clusterConfig localconfig.Cluster,
bccsp bccsp.BCCSP,
) (*BlockPullerCreator, error) {
stdDialer := &cluster.StandardDialer{
Config: baseDialer.Config,
}
stdDialer.Config.AsyncConnect = false
stdDialer.Config.SecOpts.VerifyCertificate = nil
der, _ := pem.Decode(stdDialer.Config.SecOpts.Certificate)
if der == nil {
return nil, errors.Errorf("client certificate isn't in PEM format: %v",
string(stdDialer.Config.SecOpts.Certificate))
}
factory := &BlockPullerCreator{
channelID: channelID,
bccsp: bccsp,
blockSigVerifierFactory: &deliverclient.BlockVerifierAssembler{
Logger: logger,
BCCSP: bccsp,
},
clusterConfig: clusterConfig,
signer: signer,
stdDialer: stdDialer,
der: der,
ClusterVerifyBlocks: cluster.VerifyBlocksBFT, // The default block sequence verification method.
vb: cluster.BlockVerifierBuilder(bccsp),
}
View on GitHub (pinned to 2736b63f8f)
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
Example fix
// before (yaml)
tls:
clientKey:
file: /path/to/client.cer # DER binary
clientCert:
file: /path/to/client.cer
// after
tls:
clientKey:
file: /path/to/client.key
clientCert:
file: /path/to/client-cert.pem # '-----BEGIN CERTIFICATE-----' Defensive patterns
Strategy: validation
Validate before calling
certPEM, err := os.ReadFile(cfg.TLS.ClientCertFile)
if err != nil {
return fmt.Errorf("cannot read client cert: %w", err)
}
block, _ := pem.Decode(certPEM)
if block == nil || block.Type != "CERTIFICATE" {
return fmt.Errorf("client cert %s is not PEM-encoded", cfg.TLS.ClientCertFile)
}
if _, err := x509.ParseCertificate(block.Bytes); err != nil {
return fmt.Errorf("client cert is not a valid certificate: %w", err)
} Type guard
func isPEMCertificate(data []byte) bool {
block, _ := pem.Decode(data)
return block != nil && block.Type == "CERTIFICATE"
} Try / catch
creator, err := blockpuller.NewBlockPullerCreator(...)
if err != nil {
if strings.Contains(err.Error(), "client certificate isn't in PEM format") {
return fmt.Errorf("TLS client certificate invalid; re-export PEM from MSP: %w", err)
}
return err
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- failed to add ca-file PEM to cert pool
- %s: wrong PEM encoding
- failed to access client TLS configuration: %w
- panic(err)
- server root CA cert is nil
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/2c8987000a12d5d9.
Report an issue: GitHub.