hyperledger/fabric · error

no PEM data found in cert[% x]

Error message

no PEM data found in cert[% x]

What it means

parseCertificateFromBytes decodes a consenter's TLS cert with pem.Decode; this error means the byte slice contained no PEM block, so no x509 certificate can be parsed. The message includes the raw hex of the offending bytes for diagnosis.

Source

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

		if consenter == nil {
			return errors.Errorf("metadata has nil consenter")
		}
		if err := validateConsenterTLSCerts(consenter, verifyOpts, true); err != nil {
			return errors.WithMessagef(err, "consenter %s:%d has invalid certificate", consenter.GetHost(), consenter.GetPort())
		}
	}

	if err := MetadataHasDuplication(metadata); err != nil {
		return err
	}

	return nil
}

func parseCertificateFromBytes(cert []byte) (*x509.Certificate, error) {
	pemBlock, _ := pem.Decode(cert)
	if pemBlock == nil {
		return &x509.Certificate{}, errors.Errorf("no PEM data found in cert[% x]", cert)
	}

	certificate, err := x509.ParseCertificate(pemBlock.Bytes)
	if err != nil {
		return nil, errors.Errorf("%s TLS certificate has invalid ASN1 structure %s", err, string(pemBlock.Bytes))
	}

	return certificate, nil
}

func parseCertificateListFromBytes(certs [][]byte) ([]*x509.Certificate, error) {
	var certificateList []*x509.Certificate

	for _, cert := range certs {
		certificate, err := parseCertificateFromBytes(cert)
		if err != nil {
			return certificateList, err
		}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Inspect the hex in the message to see what bytes were actually provided (empty vs non-PEM).
  2. Ensure ServerTlsCert and ClientTlsCert are PEM-encoded certificates (BEGIN CERTIFICATE/END CERTIFICATE) of the orderer's TLS keypair.
  3. Re-encode the cert file as PEM (openssl x509 -in cert.der -out cert.pem) or fix the file path in the orderer config.
  4. Regenerate the channel config update with corrected consenter certificates.

Example fix

// before: raw/der bytes
consenter.ServerTlsCert = derBytes
// after: PEM-encoded
tsCertPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
consenter.ServerTlsCert = tsCertPEM
Defensive patterns

Strategy: validation

Validate before calling

func isPEMCert(b []byte) bool {
	block, _ := pem.Decode(b)
	return block != nil && block.Type == "CERTIFICATE"
}
// apply to each consenter
if !isPEMCert(consenter.GetServerTlsCert()) || !isPEMCert(consenter.GetClientTlsCert()) {
	return errors.New("consenter TLS certs must be PEM-encoded certificates")
}

Type guard

func hasPEMCerts(c *etcdraft.Consenter) bool {
	return isPEMCert(c.GetServerTlsCert()) && isPEMCert(c.GetClientTlsCert())
}

Try / catch

if err := VerifyConfigMetadata(meta, opts); err != nil {
	if strings.Contains(err.Error(), "no PEM data found") {
		return fmt.Errorf("replace consenter TLS cert with PEM file: %v", err)
	}
	return err
}

Prevention

When it happens

Trigger: validateConsenterTLSCerts called with a consenter whose ServerTlsCert or ClientTlsCert is empty, base64-encoded-only data, a DER binary without PEM armor, or random garbage.

Common situations: configtx.yaml pointing at the wrong file for TLS certs; pasting a certificate without BEGIN/END lines; certs stored base64 in YAML and encoded again; empty cert file on the orderer; mixing up signing cert with TLS cert in channel config.

Related errors


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