hyperledger/fabric · error

error loading TLS root certificate (%s)

Error message

error loading TLS root certificate (%s)

What it means

GetServerConfig builds the peer's comm.ServerConfig, including TLS options. When peer.tls.rootcert.file is set, it reads that file to populate ServerRootCAs; if os.ReadFile fails (missing file, bad path, permission denied), the read error is wrapped with this message and returned, aborting server config creation.

Source

Thrown at core/peer/config.go:426

		if serverConfig.SecOpts.RequireClientCert {
			var clientRoots [][]byte
			for _, file := range viper.GetStringSlice("peer.tls.clientRootCAs.files") {
				clientRoot, err := os.ReadFile(
					config.TranslatePath(filepath.Dir(viper.ConfigFileUsed()), file),
				)
				if err != nil {
					return serverConfig,
						fmt.Errorf("error loading client root CAs (%s)", err)
				}
				clientRoots = append(clientRoots, clientRoot)
			}
			serverConfig.SecOpts.ClientRootCAs = clientRoots
		}
		// check for root cert
		if config.GetPath("peer.tls.rootcert.file") != "" {
			rootCert, err := os.ReadFile(config.GetPath("peer.tls.rootcert.file"))
			if err != nil {
				return serverConfig, fmt.Errorf("error loading TLS root certificate (%s)", err)
			}
			serverConfig.SecOpts.ServerRootCAs = [][]byte{rootCert}
		}
	}
	// get the default keepalive options
	serverConfig.KaOpts = comm.DefaultKeepaliveOptions
	// check to see if interval is set for the env
	if viper.IsSet("peer.keepalive.interval") {
		serverConfig.KaOpts.ServerInterval = viper.GetDuration("peer.keepalive.interval")
	}
	// check to see if timeout is set for the env
	if viper.IsSet("peer.keepalive.timeout") {
		serverConfig.KaOpts.ServerTimeout = viper.GetDuration("peer.keepalive.timeout")
	}
	// check to see if minInterval is set for the env
	if viper.IsSet("peer.keepalive.minInterval") {
		serverConfig.KaOpts.ServerMinInterval = viper.GetDuration("peer.keepalive.minInterval")
	}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Verify the file at peer.tls.rootcert.file exists and is readable by the peer process (ls -l / cat the path).
  2. Fix the path in core.yaml or CORE_PEER_TLS_ROOTCERT_FILE to an absolute path.
  3. If running in a container, ensure the secret/configmap volume is mounted before the peer starts and the path matches.
  4. Check file permissions (readable by the peer's OS user).
  5. If TLS is not intended, remove peer.tls.rootcert.file from config so the block is skipped.

Example fix

// before (core.yaml)
peer:
  tls:
    rootcert.file: tls/ca.crt   # file does not exist
// after
peer:
  tls:
    rootcert.file: /etc/hyperledger/fabric/tls/ca.crt  # absolute, existing path
Defensive patterns

Strategy: validation

Validate before calling

path := config.GetPath("peer.tls.rootcert.file")
if path != "" {
  if fi, err := os.Stat(path); err != nil {
    return fmt.Errorf("TLS root cert unreadable at %s: %w", path, err)
  } else if fi.IsDir() {
    return fmt.Errorf("%s is a directory, expected a PEM file", path)
  }
}

Try / catch

serverConfig, err := GetServerConfig()
if err != nil && strings.Contains(err.Error(), "error loading TLS root certificate") {
  log.Fatalf("fix peer.tls.rootcert.file path/permissions: %v", err)
}

Prevention

When it happens

Trigger: Calling GetServerConfig (directly or via serve/createChaincodeServer) while peer.tls.rootcert.file is configured in core.yaml/environment but points to a nonexistent, unreadable, or empty-path-resolved file.

Common situations: Docker/Kubernetes deployments mounting TLS secrets at a different path than core.yaml expects; typo in peer.tls.rootcert.file; file not mounted before peer startup; permission denied for the peer process user; relative path resolved against wrong working directory.

Understand the failure class

Related errors


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