hyperledger/fabric · critical
Header.DataHash is different from Hash(block.Data) for block
Error message
Header.DataHash is different from Hash(block.Data) for block with id [%d] on channel [%s]; Header: %s, Data: %s
What it means
VerifyBlock checks that block.Header.DataHash equals the computed hash of block.Data. A mismatch means the block header does not describe the data it carries — the block is tampered, corrupted, or fabricated — so the deliver client rejects it with this detailed message (header hash vs computed hash, hex-encoded).
Source
Thrown at common/deliverclient/block_verification.go:260
// VerifyBlock checks block integrity and its relation to the chain, and verifies the signatures.
func (a *BlockVerificationAssistant) VerifyBlock(block *common.Block) error {
if err := a.verifyHeader(block); err != nil {
return err
}
if err := a.verifyMetadata(block); err != nil {
return err
}
dataHash, err := protoutil.BlockDataHash(block.Data)
if err != nil {
return errors.Wrapf(err, "failed to verify transactions are well formed for block with id [%d] on channel [%s]", block.Header.Number, a.channelID)
}
// Verify that Header.DataHash is equal to the hash of block.Data
// This is to ensure that the header is consistent with the data carried by this block
if !bytes.Equal(dataHash, block.Header.DataHash) {
return errors.Errorf("Header.DataHash is different from Hash(block.Data) for block with id [%d] on channel [%s]; Header: %s, Data: %s",
block.Header.Number, a.channelID, hex.EncodeToString(block.Header.DataHash), hex.EncodeToString(dataHash))
}
err = a.sigVerifierFunc(block.Header, block.Metadata)
if err != nil {
return err
}
a.lastBlockHeader = block.Header
a.lastBlockHeaderHash = protoutil.BlockHeaderHash(block.Header)
return nil
}
// VerifyBlockAttestation does the same as VerifyBlock, except it assumes block.Data = nil. It therefore does not
// compute the block.Data.Hash() and compare it to the block.Header.DataHash. This is used when the orderer
// delivers a block with header & metadata only, as an attestation of block existence.
func (a *BlockVerificationAssistant) VerifyBlockAttestation(block *common.Block) error {View on GitHub (pinned to 2736b63f8f)
Solutions
- Re-fetch the block from a trusted orderer; if the mismatch persists across sources, investigate the orderer/consensus.
- Re-anchor the verification assistant with the correct last block header hash (clone/lastBlockHeader state) if the mismatch starts at one block.
- Check ledger file integrity (fsck, checksums, backup restore) for persisted blocks.
- Never hand-set Header.DataHash; compute it with protoutil.BlockDataHash(block.Data).
Example fix
// before (hand-built block)
block := &common.Block{Header: &common.BlockHeader{Number: n}} // DataHash unset/wrong
// after
block.Header.DataHash = protoutil.BlockDataHash(block.Data) Defensive patterns
Strategy: validation
Validate before calling
dataHash, err := protoutil.BlockDataHash(block.Data)
if err != nil { return err }
if !bytes.Equal(dataHash, block.Header.DataHash) {
return fmt.Errorf("block %d data hash mismatch; do not process this block", block.Header.Number)
} Type guard
func dataHashConsistent(block *common.Block) bool {
if block == nil || block.Header == nil || block.Data == nil { return false }
h, err := protoutil.BlockDataHash(block.Data)
return err == nil && bytes.Equal(h, block.Header.DataHash)
} Try / catch
if err := bva.VerifyBlock(block, opts); err != nil {
if strings.Contains(err.Error(), "different from Hash(block.Data)") {
// treat block as tampered/corrupt: refetch from trusted orderer, alert
}
return err
} Prevention
- Compute Header.DataHash with protoutil.BlockDataHash, never by hand
- Treat hash mismatches as integrity incidents: refetch, verify chain, alert
- Keep signed backups/checksums of persisted block files
- Only trust blocks delivered over authenticated TLS streams from configured orderers
When it happens
Trigger: A block delivered by an untrusted/broken orderer whose header was computed over different data; data bytes altered in transit or storage; a hand-built block whose Header.DataHash wasn't computed with protoutil.BlockDataHash.
Common situations: Chain verification across restarts picking a wrong last-block anchor; corrupted ledger storage; hand-crafted blocks in test tooling; man-in-the-middle / misbehaving orderer scenarios.
Related errors
- last block header hash is missing
- failed to verify transactions are well formed for block with
- block with id [%d] on channel [%s] does not have metadata or
- failed to initialize block verifier function
- data mismatch
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/87148d84cdd565f2.
Report an issue: GitHub.