hyperledger/fabric · error

tls root cert file must be set

Error message

tls root cert file must be set

What it means

When TLS is enabled for the peer connection (SecOpts.UseTLS), NewPeerClientForAddress requires a TLS root certificate file to verify the peer's server certificate. If tlsRootCertFile is empty while TLS is on, this error is thrown. It enforces that secure connections always have a trust anchor.

Source

Thrown at internal/peer/common/peerclient.go:67

	secOpts := comm.SecureOptions{
		UseTLS:             viper.GetBool("peer.tls.enabled"),
		RequireClientCert:  viper.GetBool("peer.tls.clientAuthRequired"),
		ServerNameOverride: viper.GetString("peer.tls.serverhostoverride"),
	}

	if secOpts.RequireClientCert {
		var err error
		secOpts.Key, secOpts.Certificate, err = getClientAuthInfoFromEnv("peer")
		if err != nil {
			return nil, err
		}

	}
	clientConfig.SecOpts = secOpts

	if clientConfig.SecOpts.UseTLS {
		if tlsRootCertFile == "" {
			return nil, errors.New("tls root cert file must be set")
		}
		caPEM, res := os.ReadFile(tlsRootCertFile)
		if res != nil {
			return nil, errors.WithMessagef(res, "unable to load TLS root cert file from %s", tlsRootCertFile)
		}
		clientConfig.SecOpts.ServerRootCAs = [][]byte{caPEM}
	}

	clientConfig.MaxRecvMsgSize = comm.DefaultMaxRecvMsgSize
	if viper.IsSet("peer.maxRecvMsgSize") {
		clientConfig.MaxRecvMsgSize = int(viper.GetInt32("peer.maxRecvMsgSize"))
	}
	clientConfig.MaxSendMsgSize = comm.DefaultMaxSendMsgSize
	if viper.IsSet("peer.maxSendMsgSize") {
		clientConfig.MaxSendMsgSize = int(viper.GetInt32("peer.maxSendMsgSize"))
	}

	return newPeerClientForClientConfig(address, clientConfig)

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Provide the TLS root cert: NewPeerClientForAddress(addr, "/path/to/tlsca.cert")
  2. Pass --tlsRootCertFile on the CLI command pointing at the network's tlsca certificate
  3. If TLS is genuinely disabled, check why UseTLS is true (peer.tls.enabled setting) and correct the config

Example fix

// before
client, err := common.NewPeerClientForAddress("peer0.org1.example.com:7051", "")
// after
client, err := common.NewPeerClientForAddress("peer0.org1.example.com:7051",
    "../test-network/organizations/peerOrganizations/org1.example.com/tlsca/tlsca.org1.example.com-cert.pem")
Defensive patterns

Strategy: validation

Validate before calling

func tlsCertReady(tlsRootCertFile string) error {
    tlsEnabled := viper.GetBool("peer.tls.enabled") || viper.GetBool("peer.tls.rootcert.file") != ""
    if tlsEnabled && tlsRootCertFile == "" {
        return errors.New("TLS is enabled but tlsRootCertFile is empty")
    }
    if tlsRootCertFile != "" {
        if _, err := os.ReadFile(tlsRootCertFile); err != nil {
            return fmt.Errorf("cannot read TLS root cert: %w", err)
        }
    }
    return nil
}

Try / catch

client, err := common.NewPeerClientForAddress(addr, tlsRootCertFile)
if err != nil {
    if strings.Contains(err.Error(), "tls root cert file must be set") {
        return fmt.Errorf("supply --tlsRootCertFile for TLS-enabled peer: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling NewPeerClientForAddress with a TLS-enabled peer address but passing "" as tlsRootCertFile; TLS enabled in config (peer.tls.enabled=true) but the --tlsRootCertFile / tls root cert path not supplied.

Common situations: Running peer CLI commands against a TLS-enabled network without --tlsRootCertFile; config switched from TLS disabled to enabled without updating client parameters; forgetting the CA cert path when targeting a different organization's peer.

Understand the failure class

Related errors


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