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

  1. Ensure orderer.yaml General.TLS.Certificate and Cluster.ServerCertificate/Certificate point to valid PEM certificate files (not keys, not DER)
  2. Convert any DER certs to PEM (openssl x509 -inform der -out cert.pem) and restart the orderer
  3. Regenerate the channel config with configtxgen after fixing TLS cert paths in the profile so ConsenterMapping contains valid PEM
  4. 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

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


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/2df9d22d382126e4. Report an issue: GitHub.