hyperledger/fabric · error
invalid PEM block
Error message
invalid PEM block
What it means
pemToDER decodes a PEM block (server or cluster TLS cert of a consenter) to raw DER bytes so detectSelfID can match the local node against the channel's consenter list. If pem.Decode fails, this error is returned and detectSelfID/remoteNodesFromConfigBlock abort, preventing cluster setup for that channel.
Source
Thrown at orderer/consensus/smartbft/consenter.go:330
// TargetChannel extracts the channel from the given proto.Message.
// Returns an empty string on failure.
func (c *Consenter) TargetChannel(message proto.Message) string {
switch req := message.(type) {
case *ab.ConsensusRequest:
return req.Channel
case *ab.SubmitRequest:
return req.Channel
default:
return ""
}
}
func pemToDER(pemBytes []byte, id uint64, certType string, logger *flogging.FabricLogger) ([]byte, error) {
bl, _ := pem.Decode(pemBytes)
if bl == nil {
logger.Errorf("Rejecting PEM block of %s TLS cert for node %d, offending PEM is: %s", certType, id, string(pemBytes))
return nil, errors.Errorf("invalid PEM block")
}
return bl.Bytes, nil
}
func (c *Consenter) detectSelfID(consenters []*cb.Consenter) (uint64, error) {
thisNodeCertAsDER, err := pemToDER(c.Comm.NodeIdentity, 0, "server", c.Logger)
if err != nil {
c.Logger.Errorf("Failed to convert node identity certificate to DER: %s", err)
return 0, err
}
var serverCertificates []string
for _, cst := range consenters {
serverCertificates = append(serverCertificates, string(cst.Identity))
certAsDER, err := pemToDER(cst.Identity, uint64(cst.Id), "server", c.Logger)
if err != nil {
c.Logger.Errorf("Failed to convert node identity certificate to DER: %s", err)View on GitHub (pinned to 2736b63f8f)
Solutions
- Ensure orderer.yaml General.TLS.Certificate and Cluster.ServerCertificate/Certificate point to valid PEM certificate files (not keys, not DER)
- Convert any DER certs to PEM (openssl x509 -inform der -out cert.pem) and restart the orderer
- Regenerate the channel config with configtxgen after fixing TLS cert paths in the profile so ConsenterMapping contains valid PEM
- Check the log line 'Rejecting PEM block of %s TLS cert for node %d' to identify which node/cert is offending
Example fix
// before (orderer.yaml)
General:
TLS:
Certificate: /path/server.key # key file, not a PEM cert
// after
General:
TLS:
Certificate: /path/server.crt # PEM-encoded certificate Defensive patterns
Strategy: validation
Validate before calling
// Validate all TLS cert files are PEM certificates before starting the orderer
for _, p := range []string{tlsCert, clusterServerCert, clusterClientCert} {
b, err := os.ReadFile(p)
if err != nil { return err }
blk, _ := pem.Decode(b)
if blk == nil {
return fmt.Errorf("%s is not a valid PEM certificate", p)
}
if _, err := x509.ParseCertificate(blk.Bytes); err != nil { return err }
} Prevention
- Point TLS config entries at certificate files, never private keys
- Use consistent PEM encoding across all cluster nodes' certs
- Regenerate channel config after any TLS cert change
- Run a preflight PEM check script in deployment automation
When it happens
Trigger: A consenter's TLS certificate bytes — from the node's own Comm.NodeIdentity or from a config block's consenter TLS_Certs — are not decodable PEM: empty cert, DER-only cert, or malformed/extra text in the metadata of the block.
Common situations: Orderer TLS material misconfigured (wrong file or DER format); a channel config built with malformed consenter TLS certs; certificate rotation replacing PEM certs with non-PEM; configtx.yaml pointing at key files instead of cert files.
Related errors
- session binding read failed
- node identity certificate %s is not a valid PEM
- cannot get HeightsByEndpoints
- cannot create BFT block deliverer
- cannot get HeightsByEndpoints
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/2df9d22d382126e4.
Report an issue: GitHub.