hyperledger/fabric · error
peer.tls.key.file and peer.tls.cert.file must both be set or
Error message
peer.tls.key.file and peer.tls.cert.file must both be set or must both be empty
What it means
Within GetClientCertificate, when neither clientKey/clientCert is set, the code falls back to the server keypair paths peer.tls.key.file and peer.tls.cert.file (relevant when clientAuthEnabled). If exactly one of those two is set, the configuration is inconsistent and this error is returned.
Source
Thrown at core/peer/config.go:483
if keyPath != "" || certPath != "" {
// need both keyPath and certPath to be set
if keyPath == "" || certPath == "" {
return cert, errors.New("peer.tls.clientKey.file and " +
"peer.tls.clientCert.file must both be set or must both be empty")
}
keyPath = config.GetPath("peer.tls.clientKey.file")
certPath = config.GetPath("peer.tls.clientCert.file")
} else {
// use the TLS server keypair
keyPath = viper.GetString("peer.tls.key.file")
certPath = viper.GetString("peer.tls.cert.file")
if keyPath != "" || certPath != "" {
// need both keyPath and certPath to be set
if keyPath == "" || certPath == "" {
return cert, errors.New("peer.tls.key.file and " +
"peer.tls.cert.file must both be set or must both be empty")
}
keyPath = config.GetPath("peer.tls.key.file")
certPath = config.GetPath("peer.tls.cert.file")
} else {
return cert, errors.New("must set either " +
"[peer.tls.key.file and peer.tls.cert.file] or " +
"[peer.tls.clientKey.file and peer.tls.clientCert.file]" +
"when peer.tls.clientAuthEnabled is set to true")
}
}
// get the keypair from the file system
clientKey, err := os.ReadFile(keyPath)
if err != nil {
return cert, errors.WithMessage(err,
"error loading client TLS key")
}
clientCert, err := os.ReadFile(certPath)View on GitHub (pinned to 2736b63f8f)
Solutions
- Set both peer.tls.key.file and peer.tls.cert.file (CORE_PEER_TLS_KEY_FILE and CORE_PEER_TLS_CERT_FILE) to valid paths.
- Or configure the explicit client pair peer.tls.clientKey.file and peer.tls.clientCert.file together.
- If neither is intended, remove both keys — but note clientAuthEnabled=true requires one complete pair.
Example fix
// before (core.yaml)
peer:
tls:
key.file: /etc/hyperledger/fabric/tls/server.key
# cert.file missing
// after
peer:
tls:
key.file: /etc/hyperledger/fabric/tls/server.key
cert.file: /etc/hyperledger/fabric/tls/server.crt Defensive patterns
Strategy: validation
Validate before calling
keyPath := viper.GetString("peer.tls.key.file")
certPath := viper.GetString("peer.tls.cert.file")
if (keyPath == "") != (certPath == "") {
return errors.New("server key and cert must both be set or both empty")
} Try / catch
cert, err := GetClientCertificate()
if err != nil && strings.Contains(err.Error(), "peer.tls.key.file and peer.tls.cert.file") {
log.Fatalf("incomplete TLS key/cert pair: %v", err)
} Prevention
- Never partially comment the TLS config block
- Emit key and cert env vars together from templates
- CI-validate TLS config before deploy
When it happens
Trigger: Calling GetClientCertificate with peer.tls.clientAuthEnabled=true, no clientKey/clientCert pair, and only one of peer.tls.key.file / peer.tls.cert.file configured.
Common situations: Setting CORE_PEER_TLS_KEY_FILE without CORE_PEER_TLS_CERT_FILE in the peer env; partially commented-out TLS block in core.yaml; automation that overwrites one of the two paths.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- peer.tls.clientKey.file and peer.tls.clientCert.file must bo
- must set either [peer.tls.key.file and peer.tls.cert.file] o
- error loading TLS root certificate (%s)
- cannot load consenter config for orderer type %s: %s
- no TLS certificate sent
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/fb83da0b17d61228.
Report an issue: GitHub.