hyperledger/fabric · critical
computed hash of block (%d) (%s) doesn't match claimed hash
Error message
computed hash of block (%d) (%s) doesn't match claimed hash (%s)
What it means
VerifyBlockHash computed SHA-256 over the block's Data via protoutil.BlockDataHash and it does not equal the DataHash stored in the block's header. This means the block payload was altered after the header was signed/committed, or the wrong bytes were deserialized into Data. This is genuine evidence of data corruption or a tampered/corrupted block.
Source
Thrown at orderer/common/cluster/util.go:238
return errors.Errorf("index %d out of bounds (total %d blocks)", indexInBuffer, len(blockBuff))
}
block := blockBuff[indexInBuffer]
if block.Header == nil {
return errors.New("missing block header")
}
if block.Data == nil {
return errors.New("missing block data")
}
seq := block.Header.Number
dataHash, err := protoutil.BlockDataHash(block.Data)
if err != nil {
return err
}
// Verify data hash matches the hash in the header
if !bytes.Equal(dataHash, block.Header.DataHash) {
computedHash := hex.EncodeToString(dataHash)
claimedHash := hex.EncodeToString(block.Header.DataHash)
return errors.Errorf("computed hash of block (%d) (%s) doesn't match claimed hash (%s)",
seq, computedHash, claimedHash)
}
// We have a previous block in the buffer, ensure current block's previous hash matches the previous one.
if indexInBuffer > 0 {
prevBlock := blockBuff[indexInBuffer-1]
currSeq := block.Header.Number
if prevBlock.Header == nil {
return errors.New("previous block header is nil")
}
prevSeq := prevBlock.Header.Number
if prevSeq+1 != currSeq {
return errors.Errorf("sequences %d and %d were received consecutively", prevSeq, currSeq)
}
if !bytes.Equal(block.Header.PreviousHash, protoutil.BlockHeaderHash(prevBlock.Header)) {
claimedPrevHash := hex.EncodeToString(block.Header.PreviousHash)
actualPrevHash := hex.EncodeToString(protoutil.BlockHeaderHash(prevBlock.Header))
return errors.Errorf("block [%d]'s hash (%s) mismatches block [%d]'s prev block hash (%s)",
prevSeq, actualPrevHash, currSeq, claimedPrevHash)View on GitHub (pinned to 2736b63f8f)
Solutions
- Do not use the affected block; force re-pull from a different orderer (restart the onboarding/catch-up process).
- Run filesystem/storage integrity checks (fsck, SMART) on the orderer's ledger volume.
- Verify the source orderer is an approved consenter and TLS certificates are correct to rule out a spoofed source.
- If a persisted block fails verification, restore the ledger from a snapshot or rejoin the node to the channel.
Example fix
// before
// trusting any block received over the wire
blockBuff = append(blockBuff, receivedBlock)
// after
if err := cluster.VerifyBlockHash(0, []*common.Block{receivedBlock}); err != nil {
logger.Errorf("discarding corrupt block: %s", err)
return err // re-pull from another orderer
}
blockBuff = append(blockBuff, receivedBlock) Defensive patterns
Strategy: fallback
Validate before calling
computed, err := protoutil.BlockDataHash(b.Data)
if err != nil || !bytes.Equal(computed, b.Header.DataHash) {
return errors.New("block data hash mismatch, re-pull required")
} Try / catch
if err := cluster.VerifyBlockHash(idx, buff); err != nil {
if strings.Contains(err.Error(), "doesn't match claimed hash") {
// corrupt block: discard and re-pull from a different orderer
logger.Errorf("corrupt block detected: %s", err)
restartCatchupFromDifferentSource()
return
}
return err
} Prevention
- Verify every block's hash chain immediately on receipt, before writing to the ledger.
- Pull blocks only from validated consenters over mutual TLS.
- Monitor disks for corruption and keep ledger volumes healthy (RAID, fsck, SMART).
- Keep an onboarding fallback: re-pull from a different orderer or restore from a verified snapshot.
When it happens
Trigger: A block pulled during replication (BlockPuller/verifyBlockSequence) whose Data bytes hash to something other than Header.DataHash — e.g. storage corruption, partial writes, or a malicious/misbehaving source.
Common situations: Disk corruption on an orderer's ledger; flaky storage/network flipping bytes during block transfer; pulling blocks from a rogue orderer that is not part of the consenter set.
Related errors
- index %d out of bounds (total %d blocks)
- missing block header
- missing block data
- block [%d]'s hash (%s) mismatches block [%d]'s prev block ha
- last block header hash is missing
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/37fadf5a4aa80379.
Report an issue: GitHub.