hyperledger/fabric · error

loading client cert/key pair

Error message

loading client cert/key pair: %s

What it means

When TLS is enabled, osnadmin loads the admin client's own certificate and private key via tls.LoadX509KeyPair from --client-cert and --client-key. If either file cannot be read or the pair is invalid (mismatched key/cert, bad PEM), this error is returned and the command exits. The orderer's admin API requires client TLS certificates to authenticate requests.

Solutions

  1. Verify both files exist and are readable, and that you didn't swap --client-cert and --client-key.
  2. Confirm cert and key match: compare their public keys via openssl x509 -noout -modulus / openssl rsa -noout -modulus (or -pubkey comparison).
  3. Re-export a fresh client cert/key pair from the admin/OrdererAdmin MSP if rotation occurred.
  4. Decrypt the key if passphrase-protected, or regenerate an unencrypted key for automated use.

Example fix

// before (swapped flags)
osnadmin channel join ... --client-cert ./tls/server.key --client-key ./tls/server.crt
// after
osnadmin channel join ... --client-cert ./tls/server.crt --client-key ./tls/server.key
Defensive patterns

Strategy: validation

Validate before calling

if _, err := tls.LoadX509KeyPair(clientCert, clientKey); err != nil {
    log.Fatalf("client TLS material invalid: %v", err)
}
// also verify cert/key pairing by parsing both and comparing public keys

Prevention

When it happens

Trigger: --client-cert/--client-key paths missing or unreadable; cert and key not a matching pair; key encrypted (passphrase-protected); PEM blocks invalid.

Common situations: Swapping cert and key arguments; regenerated orderer TLS material while old client certs are still referenced; key generated for a different cert after rotation; encrypted keys from older tooling.

Related errors


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

Appendix: source

Thrown at cmd/osnadmin/main.go:101

		caCertPool    *x509.CertPool
		tlsClientCert tls.Certificate
	)
	// TLS enabled
	if *caFile != "" {
		osnURL = fmt.Sprintf("https://%s", *orderer)
		var err error
		caCertPool = x509.NewCertPool()
		caFilePEM, err := os.ReadFile(*caFile)
		if err != nil {
			return "", 1, fmt.Errorf("reading orderer CA certificate: %s", err)
		}
		if !caCertPool.AppendCertsFromPEM(caFilePEM) {
			return "", 1, errors.New("failed to add ca-file PEM to cert pool")
		}

		tlsClientCert, err = tls.LoadX509KeyPair(*clientCert, *clientKey)
		if err != nil {
			return "", 1, fmt.Errorf("loading client cert/key pair: %s", err)
		}
	} else { // TLS disabled
		osnURL = fmt.Sprintf("http://%s", *orderer)
	}

	var marshaledConfigBlock []byte
	if *configBlockPath != "" {
		marshaledConfigBlock, err = os.ReadFile(*configBlockPath)
		if err != nil {
			return "", 1, fmt.Errorf("reading config block: %s", err)
		}

		err = validateBlockChannelID(marshaledConfigBlock, *joinChannelID)
		if err != nil {
			return "", 1, err
		}
	}

View on GitHub (pinned to 2736b63f8f)