hyperledger/fabric · critical

cannot retrieve previous block %d

Error message

cannot retrieve previous block %d

What it means

This error is thrown by the follower Chain's pullUntilTarget when it needs the hash of block (firstBlockToPull - 1) to seed prev-hash verification, but c.ledgerResources.Block() returns nil for that block. It means the local ledger does not actually contain the block immediately before the first block the follower intends to pull, so prev-hash continuity cannot be established.

Source

Thrown at orderer/common/follower/follower_chain.go:521

}

// pullUntilTarget is given a target-height and exits without an error when it reaches that target.
// It may return with an error before the target, always returning the number of blocks pulled.
// When parameter updateEndpoints is true, the block-puller's endpoints are updated with every incoming config.
// The block-puller-factory which holds the block signature verifier is updated on every incoming config.
func (c *Chain) pullUntilTarget(targetHeight uint64, updateEndpoints bool) (uint64, error) {
	firstBlockToPull := c.ledgerResources.Height()
	if firstBlockToPull >= targetHeight {
		c.logger.Debugf("Target height (%d) is <= to our ledger height (%d), skipping pulling", targetHeight, firstBlockToPull)
		return 0, nil
	}

	var actualPrevHash []byte
	// Initialize the actual previous hash
	if firstBlockToPull > 0 {
		prevBlock := c.ledgerResources.Block(firstBlockToPull - 1)
		if prevBlock == nil {
			return 0, errors.Errorf("cannot retrieve previous block %d", firstBlockToPull-1)
		}
		actualPrevHash = protoutil.BlockHeaderHash(prevBlock.Header)
	}

	// Pull until the latest height
	for seq := firstBlockToPull; seq < targetHeight; seq++ {
		n := seq - firstBlockToPull
		select {
		case <-c.stopChan:
			c.logger.Debug("Received a stop signal")
			return n, ErrChainStopped
		default:
			nextBlock := c.blockPuller.PullBlock(seq)
			if nextBlock == nil {
				return n, errors.WithMessagef(cluster.ErrRetryCountExhausted, "failed to pull block %d", seq)
			}

			reportedPrevHash := nextBlock.Header.PreviousHash

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Verify the ledger actually contains blocks 0..firstBlockToPull-1 (check Height()) before starting the follower; re-join the channel from scratch if the ledger is incomplete.
  2. Restore the missing block(s) from a snapshot or re-sync from the ordering service by resetting the follower's onboarding state and calling Join again.
  3. Check for concurrent processes (pruning jobs, admin scripts) touching the ledger directory and stop them.
  4. Inspect logs for ledger provider errors indicating the block read failed rather than the block being absent.
Defensive patterns

Strategy: validation

Validate before calling

if h := ledgerResources.Height(); h < firstBlockToPull { return fmt.Errorf("ledger height %d does not cover block %d", h, firstBlockToPull) }

Try / catch

err := follower.Start(); if err != nil && strings.Contains(err.Error(), "cannot retrieve previous block") { /* re-join channel / reset ledger */ }

Prevention

When it happens

Trigger: pullUntilTarget is called (via pullUntilLatestWithRetry) with firstBlockToPull > 0 while the ledger's height does not cover firstBlockToPull - 1 — e.g. the ledger was truncated, deleted, or reset after height tracking was computed, or a concurrent prune removed the block.

Common situations: Admins manually deleting or corrupting the ledger files (e.g. /var/hyperledger/production/orderer) while the follower chain is running; a follower node restarted with a fresh ledger but stale join/height bookkeeping; filesystem corruption or a misconfigured ledger provider returning nil blocks.

Related errors


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