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

  1. Ensure IdBytes contains a full PEM block beginning with -----BEGIN CERTIFICATE-----
  2. Re-export the identity from the MSP signcerts file rather than re-encoding the DER
  3. Check that the cert file was not truncated or stripped of headers during copy/paste
  4. 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

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


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