hyperledger/fabric · error
identity %s for MSP %s has trailing bytes
Error message
identity %s for MSP %s has trailing bytes
What it means
IsWellFormed requires the identity PEM to decode to exactly one block: pem.Decode returns leftover bytes if extra data follows the certificate. Trailing content means the identity is not canonical and could decode differently across versions, so it is rejected, naming the identity bytes and MSP ID.
Source
Thrown at msp/mspimpl.go:956
}
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
}
if !isECDSASignedCert(cert) {
return nil
}View on GitHub (pinned to 2736b63f8f)
Solutions
- Strip everything after the first END CERTIFICATE line from the identity PEM
- Keep only the single end-entity certificate in the identity/signcerts file
- Move CA certs into the MSP cacerts/intermediatescerts folders instead of concatenating
- Re-export the identity PEM from the original enrollment output
Example fix
// before // signcerts/cert.pem: userCert + caCert concatenated // after // signcerts/cert.pem: userCert only // cacerts/ca.pem: caCert
Defensive patterns
Strategy: validation
Validate before calling
func singlePEMBlock(b []byte) bool {
blk, rest := pem.Decode(b)
return blk != nil && len(bytes.TrimSpace(rest)) == 0
} Type guard
func isCanonicalSingleCertPEM(b []byte) bool {
blk, rest := pem.Decode(b)
return blk != nil && blk.Type == "CERTIFICATE" && len(rest) == 0
} Try / catch
if err := msp.IsWellFormed(si); err != nil {
if strings.Contains(err.Error(), "trailing bytes") {
// trim everything after first END CERTIFICATE line
}
return err
} Prevention
- Keep exactly one certificate per identity PEM file
- Never concatenate CA certs into signcerts
- Sanitize copied PEM files for extra blocks/junk before use
When it happens
Trigger: IsWellFormed is called with identity.IdBytes containing a valid CERTIFICATE block followed by any additional bytes — e.g. concatenated certs, whitespace/newlines after the END line are tolerated but a second block or junk is not.
Common situations: Concatenating a user cert with the CA cert into one PEM file used as the identity; copying two certs into signcerts; pasting cert plus private key into the identity field.
Related errors
- PEM decoding resulted in an empty block
- 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/16a12694a4cd35cc.
Report an issue: GitHub.