hyperledger/fabric · error

pem type is %s, should be 'CERTIFICATE' or missing

Error message

pem type is %s, should be 'CERTIFICATE' or missing

What it means

A well-formed identity PEM must have block type CERTIFICATE (or empty, for tolerance). Any other PEM type — PRIVATE KEY, PUBLIC KEY, CSR, etc. — is rejected because the identity bytes must contain the identity's X.509 certificate. The error reports the offending type.

Source

Thrown at msp/mspimpl.go:965

// 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
	}

	if !isECDSASignedCert(cert) {
		return nil
	}

	return isIdentitySignedInCanonicalForm(cert.Signature, identity.Mspid, identity.IdBytes)
}

func isIdentitySignedInCanonicalForm(sig []byte, mspID string, pemEncodedIdentity []byte) error {
	r, s, err := utils.UnmarshalECDSASignature(sig)
	if err != nil {
		return err
	}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Supply the certificate PEM (-----BEGIN CERTIFICATE-----) from the MSP signcerts folder, not the key file
  2. Verify the PEM header line before submission: it must read BEGIN CERTIFICATE
  3. Fix path/config mix-ups between the keystore (private key) and signcerts directories
  4. Re-run fabric-ca-client enroll and copy msp/signcerts/*.pem as the identity

Example fix

// before
// IdBytes: -----BEGIN PRIVATE KEY-----...
// after
// IdBytes: -----BEGIN CERTIFICATE-----... (from msp/signcerts/cert.pem)
Defensive patterns

Strategy: validation

Validate before calling

blk, _ := pem.Decode(idBytes)
if blk == nil || (blk.Type != "CERTIFICATE" && blk.Type != "") {
	return fmt.Errorf("expected CERTIFICATE pem, got %q", blk.Type)
}

Type guard

func isCertPEM(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(), "should be 'CERTIFICATE'") {
		// wrong PEM type supplied: load from signcerts instead
	}
	return err
}

Prevention

When it happens

Trigger: IsWellFormed receives an IdBytes PEM block whose Type is e.g. 'PRIVATE KEY', 'CERTIFICATE REQUEST', 'ENCRYPTED PRIVATE KEY' — i.e. the wrong PEM file was supplied as the identity certificate.

Common situations: Pointing the SDK/identity loader at the keystore (private key) file instead of signcerts; submitting a CSR instead of the issued cert; env var or config mixups between key and cert paths.

Understand the failure class

Related errors


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