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 endsView on GitHub (pinned to 2736b63f8f)
Solutions
- Skip blocks with number less than the current ledger height (query GetBlockchainInfo first) instead of re-adding
- If height is behind, re-sync from a correct source starting exactly at bcInfo.Height
- Fix the block producer/orderer to avoid gaps; investigate ordering service for skipped numbers
- 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
- Query GetBlockchainInfo before committing and skip duplicates
- Consume blocks strictly in order from a single ordered source
- After ledger resets, restart block consumption from the new height
- Monitor for ordering-service gaps (numbers skipping) and alert early
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
- ConfigEnvelope LastUpdate did not produce the supplied confi
- error decoding the block number
- error decoding the data hash
- error decoding the previous hash
- error decoding the length of block data
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/77d1704ab6128305.
Report an issue: GitHub.