hyperledger/fabric · error
failed to decode PEM block from
Error message
failed to decode PEM block from %s
What it means
loadPrivateKey reads the key file and calls pem.Decode; if the file content is not a valid PEM block (nil result), it throws this error including the file path. The Signer requires the private key in PEM form to parse it via parsePrivateKey.
Solutions
- Convert the key to PEM: openssl pkey -inform DER -in key.der -out key.pem (or openssl ec -in key.sec1.der ... )
- Verify the file contains '-----BEGIN ... PRIVATE KEY-----' at the top
- Fix SignerConfig.KeyPath in config to point at the actual PEM private key
- Re-download/re-export the key from the MSP directory
Example fix
// before openssl pkcs8 -topk8 -inform DER -in key.der -out key.pem -nocrypt // after: config signer.key: /path/to/key.pem (PEM-encoded)
Defensive patterns
Strategy: validation
Validate before calling
b, _ := os.ReadFile(keyPath)
if blk, _ := pem.Decode(b); blk == nil {
return fmt.Errorf("%s is not PEM-encoded", keyPath)
} Type guard
func isPEMPrivateKey(b []byte) bool {
blk, _ := pem.Decode(b)
return blk != nil && strings.Contains(blk.Type, "PRIVATE KEY")
} Try / catch
s, err := signer.NewSigner(keyPath, idPath)
if err != nil {
if strings.Contains(err.Error(), "failed to decode PEM block") {
return fmt.Errorf("key %s not PEM; convert: openssl pkey -inform DER", keyPath)
}
return err
} Prevention
- Convert DER keys to PEM at enrollment time
- Check file starts with '-----BEGIN' before use
- Verify KeyPath points to the key, not the cert
When it happens
Trigger: NewSigner with a key file that is raw DER, empty, an error page, base64 without headers, or corrupted/truncated PEM; wrong path passed as SignerConfig.KeyPath so the file read succeeds but content isn't PEM.
Common situations: Key exported in DER (PKCS#8/SEC1 binary) form; key file truncated by failed download; pointing KeyPath at the certificate or some other non-PEM file; trailing whitespace-only file.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- enrollment certificate isn't a valid PEM block
- chaincode deployment spec cannot be nil in a package
- chaincode install package must be provided
- chaincode interest is nil
- chaincode interest must contain at least one chaincode
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/2d78bcdff9b92a21.
Report an issue: GitHub.
Appendix: source
Thrown at cmd/common/signer/signer.go:116
// Fabric only supports ECDSA and ed25519 at the moment.
case *ecdsa.PrivateKey:
digest := util.ComputeSHA256(msg)
return signECDSA(si.key.(*ecdsa.PrivateKey), digest)
case ed25519.PrivateKey:
return ed25519.Sign(si.key.(ed25519.PrivateKey), msg), nil
default:
return nil, errors.Errorf("found unknown private key type (%T) in msg signing", key)
}
}
func loadPrivateKey(file string) (crypto.PrivateKey, error) {
b, err := os.ReadFile(file)
if err != nil {
return nil, errors.WithStack(err)
}
bl, _ := pem.Decode(b)
if bl == nil {
return nil, errors.Errorf("failed to decode PEM block from %s", file)
}
key, err := parsePrivateKey(bl.Bytes)
if err != nil {
return nil, err
}
return key, nil
}
// Based on crypto/tls/tls.go but modified for Fabric:
func parsePrivateKey(der []byte) (crypto.PrivateKey, error) {
// OpenSSL 1.0.0 generates PKCS#8 keys.
if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
switch key := key.(type) {
// Fabric only supports ECDSA at the moment.
case *ecdsa.PrivateKey:
return key, nil
case ed25519.PrivateKey:
return key, nilView on GitHub (pinned to 2736b63f8f)