hyperledger/fabric · critical

panic(err)

Error message

panic(err)

What it means

CommonClient.Certificate retrieves the client TLS certificate from the security options; if SecOpts.ClientCertificate() returns an error (e.g. the configured cert/key files cannot be loaded or parsed), the code panics rather than returning an error. This is an intentional unrecoverable failure: the client was configured to require a client cert but none can be obtained.

Source

Thrown at internal/peer/common/common.go:105

type CommonClient struct {
	clientConfig comm.ClientConfig
	address      string
}

func newCommonClient(address string, clientConfig comm.ClientConfig) (*CommonClient, error) {
	return &CommonClient{
		clientConfig: clientConfig,
		address:      address,
	}, nil
}

func (cc *CommonClient) Certificate() tls.Certificate {
	if !cc.clientConfig.SecOpts.RequireClientCert {
		return tls.Certificate{}
	}
	cert, err := cc.clientConfig.SecOpts.ClientCertificate()
	if err != nil {
		panic(err)
	}
	return cert
}

// Dial will create a new gRPC client connection to the provided
// address. The options used for the dial are sourced from the
// ClientConfig provided to the constructor.
func (cc *CommonClient) Dial(address string) (*grpc.ClientConn, error) {
	return cc.clientConfig.Dial(address)
}

func init() {
	GetEndorserClientFnc = GetEndorserClient
	GetDefaultSignerFnc = GetDefaultSigner
	GetBroadcastClientFnc = GetBroadcastClient
	GetOrdererEndpointOfChainFnc = GetOrdererEndpointOfChain
	GetDeliverClientFnc = GetDeliverClient
	GetPeerDeliverClientFnc = GetPeerDeliverClient

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Check that the client certificate and key file paths in config (SecOpts) exist and are readable
  2. Verify the key matches the certificate (re-export the pair from your MSP if unsure)
  3. Ensure RequireClientCert is only true when valid client credentials are actually configured
  4. Wrap client construction early so the panic happens at startup, not mid-operation

Example fix

// before
// SecOpts{RequireClientCert: true, Key: nil} -> panic(err)
// after
secOpts := &fab.CommonClientConfig.SecOpts
secOpts.RequireClientCert = true
secOpts.ClientCertFile = "/path/to/client.crt"
secOpts.ClientKeyFile = "/path/to/client.key" // valid, matching pair
Defensive patterns

Strategy: validation

Validate before calling

// validate cert material before constructing the client
certFile, keyFile := cfg.ClientCertFile, cfg.ClientKeyFile
if certFile == "" || keyFile == "" { return errors.New("client cert/key required when RequireClientCert=true") }
if _, err := tls.LoadX509KeyPair(certFile, keyFile); err != nil {
    return fmt.Errorf("invalid client cert/key: %w", err)
}

Type guard

func hasValidClientCert(opts *SecOpts) bool {
    if !opts.RequireClientCert { return true }
    cert, err := opts.ClientCertificate()
    return err == nil && len(cert.Certificate) > 0
}

Try / catch

func safeCertificate(cc *common.CommonClient) (cert tls.Certificate, err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("client certificate unavailable: %v", r)
        }
    }()
    return cc.Certificate(), nil
}

Prevention

When it happens

Trigger: Constructing a CommonClient with SecOpts.RequireClientCert=true but the ClientCertificate() call fails because tls client cert/key file paths are wrong, files unreadable, or key/cert mismatch.

Common situations: CORE_VM/CLI config pointing to nonexistent cert paths; expired or malformed PEM files; key and cert pair mismatched; running in a container without the mounted certificate volume.

Related errors


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