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
- Inspect the hex in the message to see what bytes were actually provided (empty vs non-PEM).
- Ensure ServerTlsCert and ClientTlsCert are PEM-encoded certificates (BEGIN CERTIFICATE/END CERTIFICATE) of the orderer's TLS keypair.
- Re-encode the cert file as PEM (openssl x509 -in cert.der -out cert.pem) or fix the file path in the orderer config.
- 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
- Always point config at PEM files (-----BEGIN CERTIFICATE-----) for TLS certs.
- Never base64-encode certs again after storing them in YAML.
- Verify cert files are non-empty on the orderer host before generating config.
- Use openssl x509 -in cert.pem -noout to confirm certs parse before embedding.
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
- failed to add ca-file PEM to cert pool
- failed to PEM decode identity bytes: %s
- %s: wrong PEM encoding
- could not decode the PEM structure
- No suitable BFT consenter for Raft consenter: %v
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/c0932b952a80b4fa.
Report an issue: GitHub.