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

  1. 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.
  2. Or configure the explicit client pair peer.tls.clientKey.file and peer.tls.clientCert.file together.
  3. 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

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

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/fb83da0b17d61228. Report an issue: GitHub.