hyperledger/fabric · error

cannot get HeightsByEndpoints

Error message

cannot get HeightsByEndpoints

What it means

Raised in Synchronizer.synchronize when blockPuller.HeightsByEndpoints() returns an error. The orderer probes all cluster delivery endpoints to learn their ledger heights before replicating blocks; this error means the height probe itself failed for every relevant endpoint (wrapped underlying cause, e.g. all endpoints unreachable, TLS failures, or no endpoints resolved).

Source

Thrown at orderer/consensus/smartbft/synchronizer.go:91

	if err != nil {
		return nil, 0
	}

	lastConfigSqn := s.Support.Sequence()

	return viewMetadata, lastConfigSqn
}

func (s *Synchronizer) synchronize() (*types.Decision, error) {
	blockPuller, err := s.BlockPullerFactory.CreateBlockPuller(s.Support, s.ClusterDialer, s.LocalConfigCluster, s.CryptoProvider)
	if err != nil {
		return nil, errors.Wrap(err, "cannot get create BlockPuller")
	}
	defer blockPuller.Close()

	heightByEndpoint, _, err := blockPuller.HeightsByEndpoints()
	if err != nil {
		return nil, errors.Wrap(err, "cannot get HeightsByEndpoints")
	}

	s.Logger.Infof("HeightsByEndpoints: %v", heightByEndpoint)

	if len(heightByEndpoint) == 0 {
		return nil, errors.New("no cluster members to synchronize with")
	}

	var heights []uint64
	for _, value := range heightByEndpoint {
		heights = append(heights, value)
	}

	targetHeight := s.computeTargetHeight(heights)
	startHeight := s.Support.Height()
	if startHeight >= targetHeight {
		return nil, errors.Errorf("already at height of %d", targetHeight)
	}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Check the wrapped cause in the log (the error is a pkg/errors wrap) — fix the underlying connection/TLS problem it names
  2. Verify every consenter's host:port in the channel config is reachable from this orderer (test with nc/openssl s_client)
  3. Verify TLS root CAs in the channel config cover all orderer TLS certificates and hostnames match SANs
  4. Restart/repair the peer orderers so at least a quorum of the cluster is up, then let the node rejoin

Example fix

// before (orderer.yaml cluster section pointing to wrong address)
cluster:
  serverCertificate: ...wrong-cert...
// after
cluster:
  serverCertificate: /var/hyperledger/orderer/tls/server.crt
  serverPrivateKey: /var/hyperledger/orderer/tls/server.key
  # and ensure channel config consenters host:port are correct/reachable
Defensive patterns

Strategy: try-catch

Validate before calling

// Before relying on Sync, probe cluster reachability
for _, ep := range consenters {
    conn, err := tls.Dial("tcp", ep.Host+":"+ep.Port, tlsConf)
    if err != nil {
        log.Printf("consenter %s:%s unreachable: %v", ep.Host, ep.Port, err)
    } else {
        conn.Close()
    }
}

Try / catch

resp := synchronizer.Sync()
// Go: Sync returns SyncResponse; on failure it falls back to local ledger.
// Detect the error via logs or by comparing heights:
if resp.Latest.Height <= localHeight {
    // sync failed; handle degraded state from local ledger
}

Prevention

When it happens

Trigger: BlockPuller creation succeeded but HeightsByEndpoints returned an error: all remote consenter delivery endpoints refused/failed connections, TLS handshake failures with remote orderers, channel membership/endpoint resolution returned no usable endpoints, or remote orderers rejected the Deliver stream.

Common situations: Orderer joining a channel where other cluster members are down or unreachable over the cluster port; TLS certificate/CA mismatches between orderers; wrong external endpoints configured in the channel consenter entries; network partition or firewall blocking the cluster (port 7053) traffic.

Related errors


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