hyperledger/fabric · error
PEM decoding resulted in an empty block
Error message
PEM decoding resulted in an empty block
What it means
IsWellFormed deserializes a SerializedIdentity and first PEM-decodes IdBytes. If pem.Decode returns nil, the bytes are not PEM at all (no BEGIN/END block), so the identity cannot be a certificate and the library rejects it immediately.
Source
Thrown at msp/mspimpl.go:953
if len(chain) <= 1 {
return nil, fmt.Errorf("failed to traverse certificate verification chain"+
" for leaf or intermediate certificate, with subject %s", cert.Subject)
}
parentCert = chain[1]
// Sanitize
return sanitizeECDSASignedCert(cert, parentCert)
}
return cert, nil
}
// IsWellFormed checks if the given identity can be deserialized into its provider-specific form.
// In this MSP implementation, well formed means that the PEM has a Type which is either
// the string 'CERTIFICATE' or the Type is missing altogether.
func (msp *bccspmsp) IsWellFormed(identity *m.SerializedIdentity) error {
bl, rest := pem.Decode(identity.IdBytes)
if bl == nil {
return errors.New("PEM decoding resulted in an empty block")
}
if len(rest) > 0 {
return errors.Errorf("identity %s for MSP %s has trailing bytes", string(identity.IdBytes), identity.Mspid)
}
// Important: This method looks very similar to getCertFromPem(idBytes []byte) (*x509.Certificate, error)
// But we:
// 1) Must ensure PEM block is of type CERTIFICATE or is empty
// 2) Must not replace getCertFromPem with this method otherwise we will introduce
// a change in validation logic which will result in a chain fork.
if bl.Type != "CERTIFICATE" && bl.Type != "" {
return errors.Errorf("pem type is %s, should be 'CERTIFICATE' or missing", bl.Type)
}
cert, err := x509.ParseCertificate(bl.Bytes)
if err != nil {
return err
}
View on GitHub (pinned to 2736b63f8f)
Solutions
- Ensure IdBytes contains a full PEM block beginning with -----BEGIN CERTIFICATE-----
- Re-export the identity from the MSP signcerts file rather than re-encoding the DER
- Check that the cert file was not truncated or stripped of headers during copy/paste
- Validate locally: pem.Decode(bytes) returns non-nil before calling IsWellFormed
Example fix
// before
idBytes := cert.Raw // raw DER, no PEM
// after
idBytes := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}) Defensive patterns
Strategy: validation
Validate before calling
func hasPEM(b []byte) bool { blk, _ := pem.Decode(b); return blk != nil }
if !hasPEM(idBytes) { return errors.New("identity bytes are not PEM") } Type guard
func isPEMCertificate(b []byte) bool {
blk, _ := pem.Decode(b)
return blk != nil && blk.Type == "CERTIFICATE"
} Try / catch
if err := msp.IsWellFormed(si); err != nil {
if strings.Contains(err.Error(), "empty block") {
// IdBytes not PEM: re-export cert with PEM encoding
}
return err
} Prevention
- Never strip PEM headers; store certs as .pem/.crt, not raw DER
- Beware JSON/base64 round-trips that mangle PEM content
- Check file contents with head -1 (expect -----BEGIN CERTIFICATE-----)
When it happens
Trigger: Calling msp.IsWellFormed(&m.SerializedIdentity{IdBytes: ...}) or upstream validation where IdBytes is empty, truncated, or contains raw DER bytes / base64 without PEM headers.
Common situations: Storing the certificate without its BEGIN CERTIFICATE lines after JSON round-tripping; passing the DER encoding instead of the PEM; a file read that dropped the header due to encoding issues; empty signcerts directory.
Related errors
- identity %s for MSP %s has trailing bytes
- pem type is %s, should be 'CERTIFICATE' or missing
- enrollment certificate isn't a valid PEM block
- enrollment certificate should be a certificate, got a %s ins
- enrollment certificate is not a valid x509 certificate: %v
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/cffa65497fed94d8.
Report an issue: GitHub.