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]
What it means
VerifyBlock recomputes the hash of block.Data and requires it to equal Header.DataHash, proving the header matches the block payload. A mismatch means the block data was tampered with, corrupted in transit, or the header belongs to different data — the block is rejected.
Source
Thrown at internal/peer/gossip/mcs.go:160
}
if channelID != string(chainID) {
return fmt.Errorf("Invalid block's channel id. Expected [%s]. Given [%s]", chainID, channelID)
}
// - Unmarshal medatada
if block.Metadata == nil || len(block.Metadata.Metadata) == 0 {
return fmt.Errorf("Block with id [%d] on channel [%s] does not have metadata. Block not valid.", block.Header.Number, chainID)
}
dataHash, err := protoutil.BlockDataHash(block.Data)
if err != nil {
return err
}
// - 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 fmt.Errorf("Header.DataHash is different from Hash(block.Data) for block with id [%d] on channel [%s]", block.Header.Number, chainID)
}
return s.verifyHeaderAndMetadata(channelID, block)
}
func (s *MSPMessageCryptoService) verifyHeaderAndMetadata(channelID string, block *pcommon.Block) error {
// Get the policy manager for channelID
cpm := s.channelPolicyManagerGetter.Manager(channelID)
if cpm == nil {
return fmt.Errorf("Could not acquire policy manager for channel %s", channelID)
}
mcsLogger.Debugf("Got policy manager for channel [%s]", channelID)
// Get block validation policy
policy, ok := cpm.GetPolicy(policies.BlockValidation)
// ok is true if it was the policy requested, or false if it is the default policy
mcsLogger.Debugf("Got block validation policy for channel [%s] with flag [%t]", channelID, ok)
View on GitHub (pinned to 2736b63f8f)
Solutions
- Discard the block and re-fetch from the orderer or a trusted peer
- Check storage integrity (ledger/block files) if multiple blocks fail hash verification
- In code/tests, always build blocks with protoutil.CreateBlockHash/BlockDataHash so the header hash matches data
Example fix
// before block.Header.DataHash = someOtherHash // after dataHash, _ := protoutil.BlockDataHash(block.Data) block.Header.DataHash = dataHash
Defensive patterns
Strategy: validation
Validate before calling
func dataHashConsistent(b *pcommon.Block) bool {
if b == nil || b.Header == nil || b.Data == nil {
return false
}
h, err := protoutil.BlockDataHash(b.Data)
if err != nil {
return false
}
return bytes.Equal(h, b.Header.DataHash)
} Type guard
func dataHashConsistent(b *pcommon.Block) bool {
if b == nil || b.Header == nil || b.Data == nil {
return false
}
h, err := protoutil.BlockDataHash(b.Data)
if err != nil {
return false
}
return bytes.Equal(h, b.Header.DataHash)
}
if !dataHashConsistent(block) {
return errors.New("block data/header hash mismatch, discarding")
} Try / catch
if err := cryptoService.VerifyBlock(chainID, seqNum, block); err != nil {
if strings.Contains(err.Error(), "Header.DataHash is different") {
log.Errorf("corrupt/tampered block %d on %s, refetching", seqNum, chainID)
return refetchBlock(chainID, seqNum)
}
return err
} Prevention
- Never mutate block.Data after the header hash is set
- Recompute BlockDataHash after any in-memory block construction
- Investigate storage integrity if hash mismatches appear across many blocks; treat them as tamper signals
When it happens
Trigger: VerifyBlock called on a block where bytes.Equal(BlockDataHash(block.Data), block.Header.DataHash) is false — data modified after header creation, wrong serialization, or mixing fields from two blocks.
Common situations: Storage corruption in the block store; a mutated in-memory block in custom code or tests; interop problems where block data was re-encoded without updating the header hash.
Related errors
- data mismatch
- failed unmarshalling alive message
- failed unmarshalling stateInfo message
- wasn't able to read ledger height
- was not able to retrieve private data from transient store,
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/fff966461a2d0fed.
Report an issue: GitHub.