{"record":{"id":"9c610d80e5a7fab6","repo":"hyperledger/fabric","slug":"enrollment-certificate-isn-t-a-valid-pem-block","errorCode":null,"errorMessage":"enrollment certificate isn't a valid PEM block","messagePattern":"enrollment certificate isn't a valid PEM block","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/common/signer/signer.go","lineNumber":83,"sourceCode":"func serializeIdentity(clientCert string, mspID string) ([]byte, error) {\n\tb, err := os.ReadFile(clientCert)\n\tif err != nil {\n\t\treturn nil, errors.WithStack(err)\n\t}\n\tif err := validateEnrollmentCertificate(b); err != nil {\n\t\treturn nil, err\n\t}\n\tsId := &msp.SerializedIdentity{\n\t\tMspid:   mspID,\n\t\tIdBytes: b,\n\t}\n\treturn protoutil.MarshalOrPanic(sId), nil\n}\n\nfunc validateEnrollmentCertificate(b []byte) error {\n\tbl, _ := pem.Decode(b)\n\tif bl == nil {\n\t\treturn errors.Errorf(\"enrollment certificate isn't a valid PEM block\")\n\t}\n\n\tif bl.Type != \"CERTIFICATE\" {\n\t\treturn errors.Errorf(\"enrollment certificate should be a certificate, got a %s instead\", strings.ToLower(bl.Type))\n\t}\n\n\tif _, err := x509.ParseCertificate(bl.Bytes); err != nil {\n\t\treturn errors.Errorf(\"enrollment certificate is not a valid x509 certificate: %v\", err)\n\t}\n\treturn nil\n}\n\nfunc (si *Signer) Sign(msg []byte) ([]byte, error) {\n\tswitch key := si.key.(type) {\n\t// Fabric only supports ECDSA and ed25519 at the moment.\n\tcase *ecdsa.PrivateKey:\n\t\tdigest := util.ComputeSHA256(msg)\n\t\treturn signECDSA(si.key.(*ecdsa.PrivateKey), digest)","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/cmd/common/signer/signer.go#L65-L101","documentation":"validateEnrollmentCertificate parses the enrollment certificate bytes with pem.Decode; if the bytes do not form any PEM block (nil result), it throws this error. The Signer requires the identity file to be a PEM-encoded certificate, so non-PEM input is rejected early in serializeIdentity.","triggerScenarios":"Calling NewSigner (leading to serializeIdentity) with an identity file whose contents are raw DER bytes, base64 without PEM armor, an HTML/text error page, an empty file, or a file with a BOM/whitespace-only content.","commonSituations":"Certificate exported in DER format instead of PEM; accidentally downloading the cert URL instead of the cert; file truncated or empty; concatenating the wrong file as identity.","solutions":["Convert the certificate to PEM format: openssl x509 -inform DER -in cert.der -out cert.pem","Verify the file starts with '-----BEGIN CERTIFICATE-----' (cat the file, check for stray whitespace/BOM)","Re-export the enrollment certificate from the Fabric CA as PEM","Confirm the identity path in config points to the certificate, not the key or another file"],"exampleFix":"// before: identity file is raw DER bytes\n// after\nopenssl x509 -inform DER -in cert.der -out cert.pem\n# config: signer.identity: /path/to/cert.pem","handlingStrategy":"validation","validationCode":"b, _ := os.ReadFile(identityPath)\nif block, _ := pem.Decode(b); block == nil || block.Type != \"CERTIFICATE\" {\n    return fmt.Errorf(\"%s is not a PEM certificate\", identityPath)\n}","typeGuard":"func isPEMCertificate(b []byte) bool {\n    blk, _ := pem.Decode(b)\n    return blk != nil && blk.Type == \"CERTIFICATE\"\n}","tryCatchPattern":"if _, err := signer.NewSigner(keyPath, idPath); err != nil {\n    if strings.Contains(err.Error(), \"valid PEM block\") {\n        return fmt.Errorf(\"identity %s is not PEM; convert with openssl x509 -inform DER\", idPath)\n    }\n    return err\n}","preventionTips":["Always use PEM (openssl default -outform PEM) for identities","Sanity-check cert files with openssl x509 -noout -text before deployment","Don't confuse DER exports with PEM in material pipelines"],"tags":["pem","certificate","fabric","validation"],"backgroundTag":"invalid-pem-certificate","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}