hyperledger/fabric · critical
unexpected Previous block hash. Expected PreviousHash = [%x]
Error message
unexpected Previous block hash. Expected PreviousHash = [%x], PreviousHash referred in the latest block= [%x]
What it means
addBlock verifies that block.Header.PreviousHash equals the hash of the current chain tip (bcInfo.CurrentBlockHash). This cheap bytes comparison catches blocks that do not chain onto the ledger's last block, which usually indicates a fork, a block from a different chain, or an ordering-service bug. The block is rejected with this error.
Source
Thrown at common/ledger/blkstorage/blockfile_mgr.go:298
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
txOffsets := info.txOffsets
currentOffset := mgr.blockfilesInfo.latestFileSize
blockBytesLen := len(blockBytes)
blockBytesEncodedLen := protowire.AppendVarint(nil, uint64(blockBytesLen))
totalBytesToAppend := blockBytesLen + len(blockBytesEncodedLen)
// Determine if we need to start a new file since the size of this block
// exceeds the amount of space left in the current file
if currentOffset+totalBytesToAppend > mgr.conf.maxBlockfileSize {
mgr.moveToNextFile()View on GitHub (pinned to 2736b63f8f)
Solutions
- Verify the block source: reconnect to the correct ordering service / consensus cluster and re-fetch blocks from the ledger height
- Restore the ledger data from a consistent backup matching the same chain (same genesis block and orderer history)
- If the chain diverged, perform a ledger reset and re-sync from the canonical chain
- Check that genesis blocks/config match across environments before importing or syncing
Example fix
// before: trusting a stale/mismatched block feed blk := fetchFromOrderer(number) store.AddBlock(blk) // fails: PreviousHash != tip // after: re-sync from ledger height against the canonical orderer bcInfo, _ := store.GetBlockchainInfo() blk := fetchFromCanonicalOrderer(bcInfo.Height) store.AddBlock(blk)
Defensive patterns
Strategy: validation
Validate before calling
bcInfo, err := store.GetBlockchainInfo()
if err != nil { return err }
if !bytes.Equal(block.Header.PreviousHash, bcInfo.CurrentBlockHash) {
return fmt.Errorf("refusing block %d: does not chain onto tip", block.Header.Number)
} Try / catch
if err := store.AddBlock(block); err != nil {
if strings.Contains(err.Error(), "unexpected Previous block hash") {
// halt the feed, flag a possible fork/divergence, re-sync from canonical orderer
}
return err
} Prevention
- Always source blocks from the single canonical ordering service/consensus cluster
- Restore ledgers only from backups taken on the same chain (same genesis/history)
- Validate PreviousHash against GetBlockchainInfo() before committing when driving the API directly
- Investigate any occurrence immediately — it usually signals a fork or corrupted/divergent ledger
When it happens
Trigger: Adding a block whose PreviousHash differs from the stored hash of the last committed block — e.g., after restoring block files inconsistently, importing blocks from a diverged branch, or two orderers producing conflicting chains.
Common situations: Ledger restored from mixed/partial backups; peer connected to a diverged ordering service (Raft reconfiguration/fork); snapshot import combined with blocks from a different network; test harnesses reusing blocks across ledgers.
Related errors
- block [%d]'s hash (%s) mismatches block [%d]'s prev block ha
- 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/ac5a49d143242fb7.
Report an issue: GitHub.