hyperledger/fabric · info

already at height of %d

Error message

already at height of %d

What it means

Raised in Synchronizer.synchronize when the local ledger height (startHeight) is already greater than or equal to the computed target height derived from remote peers' heights. This is not a fault: it means the node has nothing to replicate — it is as up-to-date as (or ahead of) the cluster members it probed. Sync then falls back to serving state from the local ledger.

Source

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

	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)
	}

	targetSeq := targetHeight - 1
	seq := startHeight

	var blocksFetched int

	s.Logger.Debugf("Will fetch sequences [%d-%d]", seq, targetSeq)

	var lastPulledBlock *cb.Block
	for seq <= targetSeq {
		block := blockPuller.PullBlock(seq)
		if block == nil {
			s.Logger.Debugf("Failed to fetch block [%d] from cluster", seq)
			break
		}
		if protoutil.IsConfigBlock(block) {
			s.Support.WriteConfigBlock(block, nil)

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. If the node is healthy this is expected — verify the local ledger height matches the cluster and ignore
  2. Check why remote peers report low heights: are most cluster members down? Bring up a quorum
  3. If this node is erroneously ahead (restored backup), reconcile with the actual cluster ledger; do NOT truncate the ledger manually without operator procedures
  4. Ensure enough endpoints are reachable so computeTargetHeight sees the true maximum cluster height
Defensive patterns

Strategy: type-guard

Validate before calling

// Compare local height to remote heights before triggering sync
localHeight := support.Height()
remoteHeights := probeHeights(consenters) // via Deliver service
if maxOf(remoteHeights) <= localHeight {
    // node is already caught up; skip synchronization entirely
}

Try / catch

// Treat 'already at height' as success: check result height instead of error
resp := synchronizer.Sync()
if resp.Latest.Height >= expectedHeight {
    // healthy caught-up state; no action needed
}

Prevention

When it happens

Trigger: Synchronizer.Sync -> synchronize runs, HeightsByEndpoint probing succeeds, computeTargetHeight(heights) <= s.Support.Height(). Happens when this orderer is already caught up, when remote peers are lagging/behind (making targetHeight lower), or when computeTargetHeight picks a low height (e.g. f+1-th highest height with few reachable peers).

Common situations: Healthy caught-up orderer whose node still calls Sync (benign, logged as a warning); most cluster members are offline so the probe only sees laggard peers; after restoring from backup this node is ahead of the live cluster; asymmetry after network partition heals.

Related errors


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