hyperledger/fabric · error

block number should have been %d but was %d

Error message

block number should have been %d but was %d

What it means

addBlock enforces that the incoming block's Header.Number equals the current ledger height (next expected block number). If the block is a duplicate (number < height), out of order, or skipping ahead (number > height), it returns this error and the block is not committed.

Source

Thrown at common/ledger/blkstorage/blockfile_mgr.go:287

	nextFileWriter, err := newBlockfileWriter(
		deriveBlockfilePath(mgr.rootDir, blkfilesInfo.latestFileNumber),
	)
	if err != nil {
		panic(fmt.Sprintf("Could not open writer to next file: %s", err))
	}
	mgr.currentFileWriter.close()
	err = mgr.saveBlkfilesInfo(blkfilesInfo, true)
	if err != nil {
		panic(fmt.Sprintf("Could not save next block file info to db: %s", err))
	}
	mgr.currentFileWriter = nextFileWriter
	mgr.updateBlockfilesInfo(blkfilesInfo)
}

func (mgr *blockfileMgr) addBlock(block *common.Block) error {
	bcInfo := mgr.getBlockchainInfo()
	if block.Header.Number != bcInfo.Height {
		return errors.Errorf(
			"block number should have been %d but was %d",
			mgr.getBlockchainInfo().Height, block.Header.Number,
		)
	}

	// Add the previous hash check - Though, not essential but may not be a bad idea to
	// verify the field `block.Header.PreviousHash` present in the block.
	// This check is a simple bytes comparison and hence does not cause any observable performance penalty
	// and may help in detecting a rare scenario if there is any bug in the ordering service.
	if !bytes.Equal(block.Header.PreviousHash, bcInfo.CurrentBlockHash) {
		return errors.Errorf(
			"unexpected Previous block hash. Expected PreviousHash = [%x], PreviousHash referred in the latest block= [%x]",
			bcInfo.CurrentBlockHash, block.Header.PreviousHash,
		)
	}
	blockBytes, info := serializeBlock(block)
	blockHash := protoutil.BlockHeaderHash(block.Header)
	// Get the location / offset where each transaction starts in the block and where the block ends

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Skip blocks with number less than the current ledger height (query GetBlockchainInfo first) instead of re-adding
  2. If height is behind, re-sync from a correct source starting exactly at bcInfo.Height
  3. Fix the block producer/orderer to avoid gaps; investigate ordering service for skipped numbers
  4. If the ledger is wrong/stuck, reset and re-sync the ledger rather than forcing mismatched blocks

Example fix

// before: blindly adds every delivered block
for _, blk := range blocks {
    if err := store.AddBlock(blk); err != nil { return err }
}
// after: skip already-committed blocks
bcInfo, _ := store.GetBlockchainInfo()
for _, blk := range blocks {
    if blk.Header.Number < bcInfo.Height { continue }
    if err := store.AddBlock(blk); err != nil { return err }
}
Defensive patterns

Strategy: validation

Validate before calling

bcInfo, err := store.GetBlockchainInfo()
if err != nil { return err }
if block.Header.Number < bcInfo.Height {
    return nil // duplicate: already committed, skip
}
if block.Header.Number > bcInfo.Height {
    return fmt.Errorf("gap: expected %d, got %d", bcInfo.Height, block.Header.Number)
}

Try / catch

if err := store.AddBlock(block); err != nil {
    if strings.Contains(err.Error(), "block number should have been") {
        // refresh bcInfo and skip/re-sync instead of failing the whole stream
    }
    return err
}

Prevention

When it happens

Trigger: Calling AddBlock with a block whose Header.Number != current height — re-committing an already-committed block, delivering blocks out of order, or gaps in the block sequence from a misbehaving deliverer.

Common situations: Deliver/gossip client reconnecting and replaying blocks already committed; a committer receiving a block range that overlaps local height after a ledger reset; ordering-service bugs producing block gaps; application code driving the ledger API directly with wrong numbering.

Related errors


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