{"record":{"id":"37fadf5a4aa80379","repo":"hyperledger/fabric","slug":"computed-hash-of-block-d-s-doesn-t-match-cla","errorCode":null,"errorMessage":"computed hash of block (%d) (%s) doesn't match claimed hash (%s)","messagePattern":"computed hash of block \\((.+?)\\) \\((.+?)\\) doesn't match claimed hash \\((.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"orderer/common/cluster/util.go","lineNumber":238,"sourceCode":"\t\treturn errors.Errorf(\"index %d out of bounds (total %d blocks)\", indexInBuffer, len(blockBuff))\n\t}\n\tblock := blockBuff[indexInBuffer]\n\tif block.Header == nil {\n\t\treturn errors.New(\"missing block header\")\n\t}\n\tif block.Data == nil {\n\t\treturn errors.New(\"missing block data\")\n\t}\n\tseq := block.Header.Number\n\tdataHash, err := protoutil.BlockDataHash(block.Data)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// Verify data hash matches the hash in the header\n\tif !bytes.Equal(dataHash, block.Header.DataHash) {\n\t\tcomputedHash := hex.EncodeToString(dataHash)\n\t\tclaimedHash := hex.EncodeToString(block.Header.DataHash)\n\t\treturn errors.Errorf(\"computed hash of block (%d) (%s) doesn't match claimed hash (%s)\",\n\t\t\tseq, computedHash, claimedHash)\n\t}\n\t// We have a previous block in the buffer, ensure current block's previous hash matches the previous one.\n\tif indexInBuffer > 0 {\n\t\tprevBlock := blockBuff[indexInBuffer-1]\n\t\tcurrSeq := block.Header.Number\n\t\tif prevBlock.Header == nil {\n\t\t\treturn errors.New(\"previous block header is nil\")\n\t\t}\n\t\tprevSeq := prevBlock.Header.Number\n\t\tif prevSeq+1 != currSeq {\n\t\t\treturn errors.Errorf(\"sequences %d and %d were received consecutively\", prevSeq, currSeq)\n\t\t}\n\t\tif !bytes.Equal(block.Header.PreviousHash, protoutil.BlockHeaderHash(prevBlock.Header)) {\n\t\t\tclaimedPrevHash := hex.EncodeToString(block.Header.PreviousHash)\n\t\t\tactualPrevHash := hex.EncodeToString(protoutil.BlockHeaderHash(prevBlock.Header))\n\t\t\treturn errors.Errorf(\"block [%d]'s hash (%s) mismatches block [%d]'s prev block hash (%s)\",\n\t\t\t\tprevSeq, actualPrevHash, currSeq, claimedPrevHash)","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/cluster/util.go#L220-L256","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n// trusting any block received over the wire\nblockBuff = append(blockBuff, receivedBlock)\n// after\nif err := cluster.VerifyBlockHash(0, []*common.Block{receivedBlock}); err != nil {\n    logger.Errorf(\"discarding corrupt block: %s\", err)\n    return err // re-pull from another orderer\n}\nblockBuff = append(blockBuff, receivedBlock)","handlingStrategy":"fallback","validationCode":"computed, err := protoutil.BlockDataHash(b.Data)\nif err != nil || !bytes.Equal(computed, b.Header.DataHash) {\n    return errors.New(\"block data hash mismatch, re-pull required\")\n}","typeGuard":null,"tryCatchPattern":"if err := cluster.VerifyBlockHash(idx, buff); err != nil {\n    if strings.Contains(err.Error(), \"doesn't match claimed hash\") {\n        // corrupt block: discard and re-pull from a different orderer\n        logger.Errorf(\"corrupt block detected: %s\", err)\n        restartCatchupFromDifferentSource()\n        return\n    }\n    return err\n}","preventionTips":["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."],"tags":["blockchain","block-verification","hash-mismatch","data-corruption"],"backgroundTag":"block-hash-mismatch","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}