hyperledger/fabric · error

my consenter certificate %s is not a valid PEM

Error message

my consenter certificate %s is not a valid PEM

What it means

IsConsenterOfChannel decodes the consenter's own certificate with pem.Decode; if the result is nil the bytes are not a valid PEM block, and the error embeds the raw certificate bytes as a string. The library throws it because it cannot extract the DER certificate needed to compare against the consenters listed in the channel's etcdraft ConfigMetadata.

Source

Thrown at orderer/consensus/etcdraft/util.go:384

	if err != nil {
		return err
	}
	bundle, err := channelconfig.NewBundleFromEnvelope(envelopeConfig, conCert.CryptoProvider)
	if err != nil {
		return err
	}
	oc, exists := bundle.OrdererConfig()
	if !exists {
		return errors.New("no orderer config in bundle")
	}
	m := &etcdraft.ConfigMetadata{}
	if err := proto.Unmarshal(oc.ConsensusMetadata(), m); err != nil {
		return err
	}

	bl, _ := pem.Decode(conCert.ConsenterCertificate)
	if bl == nil {
		return errors.Errorf("my consenter certificate %s is not a valid PEM", string(conCert.ConsenterCertificate))
	}

	myCertDER := bl.Bytes

	var failedMatches []string
	for _, consenter := range m.GetConsenters() {
		candidateBlock, _ := pem.Decode(consenter.GetServerTlsCert())
		if candidateBlock == nil {
			return errors.Errorf("candidate server certificate %s is not a valid PEM", string(consenter.GetServerTlsCert()))
		}
		sameServerCertErr := crypto.CertificatesWithSamePublicKey(myCertDER, candidateBlock.Bytes)

		candidateBlock, _ = pem.Decode(consenter.GetClientTlsCert())
		if candidateBlock == nil {
			return errors.Errorf("candidate client certificate %s is not a valid PEM", string(consenter.GetClientTlsCert()))
		}
		sameClientCertErr := crypto.CertificatesWithSamePublicKey(myCertDER, candidateBlock.Bytes)

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Point the consenter certificate configuration at a PEM-encoded X.509 certificate file (-----BEGIN CERTIFICATE-----), not a key or DER file
  2. Regenerate the consenter certificate from the org CA and pass it as PEM (openssl x509 -in cert.crt -out cert.pem if needed)
  3. Verify the file/env providing the cert is actually mounted and non-empty at orderer startup

Example fix

// before: raw DER or key material passed
conCert := ConsenterCertificate{ConsenterCertificate: derBytes}
// after: ensure PEM-encoded certificate
pemBytes, err := os.ReadFile("consenter-cert.pem") // contains -----BEGIN CERTIFICATE-----
if err != nil { return err }
conCert := ConsenterCertificate{ConsenterCertificate: pemBytes}
Defensive patterns

Strategy: validation

Validate before calling

func isPEMCertificate(b []byte) bool {
    block, _ := pem.Decode(b)
    if block == nil || block.Type != "CERTIFICATE" { return false }
    _, err := x509.ParseCertificate(block.Bytes)
    return err == nil
}

Type guard

func hasValidConsenterCert(c ConsenterCertificate) bool {
    return isPEMCertificate(c.ConsenterCertificate)
}

Prevention

When it happens

Trigger: ConsenterCertificate.ConsenterCertificate contains an empty slice, raw DER bytes without PEM armor, a private key file, or text/garbage instead of a PEM-encoded X.509 certificate.

Common situations: GeneralGenesisFile/TLS genesis material misconfigured so the consenter cert field points at a key or wrong file; certificate passed as base64 instead of PEM; empty env var or mount for the consenter certificate at orderer startup.

Understand the failure class

Related errors


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