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
- Supply the certificate PEM (-----BEGIN CERTIFICATE-----) from the MSP signcerts folder, not the key file
- Verify the PEM header line before submission: it must read BEGIN CERTIFICATE
- Fix path/config mix-ups between the keystore (private key) and signcerts directories
- 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
- Separate key and cert paths in configuration; double-check env vars
- Name files clearly (cert.pem vs key.pem) to avoid mix-ups
- Grep the PEM header type before loading identity material
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
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- PEM decoding resulted in an empty block
- identity %s for MSP %s has trailing bytes
- %s is mandatory and cannot be empty
- enrollment certificate isn't a valid PEM block
- enrollment certificate should be a certificate, got a %s ins
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/d27ecb15455649e2.
Report an issue: GitHub.