hyperledger/fabric · error
cannot get HeightsByEndpoints
Error message
cannot get HeightsByEndpoints
What it means
Raised in BFTSynchronizer.detectTargetHeight when blockPuller.HeightsByEndpoints() returns an error while probing all cluster delivery endpoints for their ledger heights. Without these heights the synchronizer cannot compute a target height, so synchronization aborts. The underlying cause (connection, TLS, or authorization failure) is wrapped and should be examined.
Source
Thrown at orderer/consensus/smartbft/synchronizer_bft.go:141
return decision, nil
}
// detectTargetHeight probes remote endpoints and detects what is the target height this node needs to reach. It also
// detects the self-endpoint.
//
// In BFT it is highly recommended that the channel/orderer-endpoints (for delivery & broadcast) map 1:1 to the
// channel/orderers/consenters (for cluster consensus), that is, every consenter should be represented by a
// delivery endpoint. This important for Sync to work properly.
func (s *BFTSynchronizer) detectTargetHeight() (uint64, string, error) {
blockPuller, err := s.BlockPullerFactory.CreateBlockPuller(s.Support, s.ClusterDialer, s.LocalConfigCluster, s.CryptoProvider)
if err != nil {
return 0, "", errors.Wrap(err, "cannot get create BlockPuller")
}
defer blockPuller.Close()
heightByEndpoint, myEndpoint, err := blockPuller.HeightsByEndpoints()
if err != nil {
return 0, "", errors.Wrap(err, "cannot get HeightsByEndpoints")
}
s.Logger.Infof("HeightsByEndpoints: %+v, my endpoint: %s", heightByEndpoint, myEndpoint)
delete(heightByEndpoint, myEndpoint)
var heights []uint64
for _, value := range heightByEndpoint {
heights = append(heights, value)
}
if len(heights) == 0 {
return 0, "", errors.New("no cluster members to synchronize with")
}
targetHeight := s.computeTargetHeight(heights)
s.Logger.Infof("Detected target height: %d", targetHeight)
return targetHeight, myEndpoint, nil
}View on GitHub (pinned to 2736b63f8f)
Solutions
- Check the wrapped inner error to identify the failing endpoint(s) and cause
- Verify every consenter endpoint is reachable and each consenter has a matching delivery endpoint (1:1)
- Fix TLS root CAs / hostnames in channel config and cluster TLS configuration
- Bring enough orderers back online so height probing can succeed, then retry
Defensive patterns
Strategy: retry
Validate before calling
// Probe all delivery endpoints before attempting sync
ok := 0
for _, ep := range consenters {
if reachable(ep.Host, ep.Port, tlsConf) { ok++ }
}
if ok == 0 {
// height probing will certainly fail; fix connectivity first
} Try / catch
resp := bftSynchronizer.Sync()
if syncFailed(resp) && endpointsWereUnreachable() {
time.Sleep(backoff)
resp = bftSynchronizer.Sync() // retriable once network/TLS restored
} Prevention
- Ensure 1:1 consenter-to-delivery-endpoint mapping in channel config
- Continuously monitor cluster-port reachability and TLS handshakes
- Keep quorum of orderers online with automated alerts
- Validate CA bundles cover all orderer TLS certificates after rotation
When it happens
Trigger: HeightsByEndpoints fails after the puller was created: all remote consenter endpoints unreachable on the cluster port, TLS handshake/rejection on Deliver streams, or endpoint resolution returning nothing usable.
Common situations: Quorum of peers offline during catch-up; firewall blocking the cluster (7053) port; TLS CA or hostname mismatches between orderers; channel consenter endpoints not mapping 1:1 to delivery endpoints (required for BFT sync, per the source comment).
Related errors
- cannot get HeightsByEndpoints
- no cluster members to synchronize with
- failed pulling block %d
- cannot get detect target height
- cannot create BFT block deliverer
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/c46d2e261dbcbf68.
Report an issue: GitHub.