{"record":{"id":"24c703822a50693b","repo":"hyperledger/fabric","slug":"header-previoushash-of-block-d-is-different-fro","errorCode":null,"errorMessage":"Header.PreviousHash of block [%d] is different from Hash(block.Header) of previous block, on channel [%s], received: %s, expected: %s","messagePattern":"Header\\.PreviousHash of block \\[(.+?)\\] is different from Hash\\(block\\.Header\\) of previous block, on channel \\[(.+?)\\], received: (.+?), expected: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"common/deliverclient/block_verification.go","lineNumber":326,"sourceCode":"\treturn nil\n}\n\nfunc (a *BlockVerificationAssistant) verifyHeader(block *common.Block) error {\n\tif block == nil {\n\t\treturn errors.Errorf(\"block must be different from nil, channel=%s\", a.channelID)\n\t}\n\tif block.Header == nil {\n\t\treturn errors.Errorf(\"invalid block, header must be different from nil, channel=%s\", a.channelID)\n\t}\n\n\texpectedBlockNum := a.lastBlockHeader.Number + 1\n\tif expectedBlockNum != block.Header.Number {\n\t\treturn errors.Errorf(\"expected block number is [%d] but actual block number inside block is [%d]\", expectedBlockNum, block.Header.Number)\n\t}\n\n\tif len(a.lastBlockHeaderHash) != 0 {\n\t\tif !bytes.Equal(block.Header.PreviousHash, a.lastBlockHeaderHash) {\n\t\t\treturn errors.Errorf(\"Header.PreviousHash of block [%d] is different from Hash(block.Header) of previous block, on channel [%s], received: %s, expected: %s\",\n\t\t\t\tblock.Header.Number, a.channelID, hex.EncodeToString(block.Header.PreviousHash), hex.EncodeToString(a.lastBlockHeaderHash))\n\t\t}\n\t}\n\treturn nil\n}\n","sourceCodeStart":308,"sourceCodeEnd":332,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/common/deliverclient/block_verification.go#L308-L332","documentation":"After the block number check, verifyHeader validates the hash chain: block.Header.PreviousHash must equal the hash of the previous block's header (stored in a.lastBlockHeaderHash). A mismatch means the delivered block is not chained onto the block the client last accepted — evidence of a corrupted stream, a fork, or data tampering.","triggerScenarios":"VerifyBlock/VerifyBlockAttestation receives a block whose PreviousHash differs from the stored lastBlockHeaderHash (only when lastBlockHeaderHash is non-empty). Occurs when the orderer serves a divergent chain, a different channel's block leaks into the stream, or the client's lastBlockHeaderHash was seeded from the wrong block.","commonSituations":"Ordering service nodes with divergent chains after a configuration/consensus fault; connecting to an orderer that was forcibly refetched/different genesis; switching endpoints mid-stream to a node on a different branch; test setups seeding lastBlockHeaderHash incorrectly.","solutions":["Verify the ordering node you are connected to is on the same chain as your peers (compare block hashes at a common height).","Reconnect to a different/orderer-consensus-quorum-backed endpoint rather than a possibly forked node.","If the client state is wrong, recompute lastBlockHeaderHash from a trusted local ledger block before resuming the stream.","If a genuine fork/tampering is suspected, halt the client and follow the chain-repair procedures for the network."],"exampleFix":"// before\n// blindly resuming stream from a possibly forked orderer\ndeliverClient.Connect(seekInfoEnv, suspectEndpoint)\n// after\nif !bytes.Equal(headersAtHeight(orderer, h).Hash(), localLedgerBlockHash(h)) {\n    endpoint = selectOrdererOnSameChain(ordererEndpoints, localLedgerBlockHash)\n}\ndeliverClient.Connect(seekInfoEnv, endpoint)","handlingStrategy":"fallback","validationCode":"if len(lastBlockHeaderHash) > 0 && !bytes.Equal(blk.Header.PreviousHash, lastBlockHeaderHash) {\n    return fmt.Errorf(\"hash chain broken at block %d; switching orderer\", blk.Header.Number)\n}","typeGuard":null,"tryCatchPattern":"if err := assistant.VerifyBlock(blk); err != nil {\n    if strings.Contains(err.Error(), \"PreviousHash of block\") {\n        // treat as possible fork: disconnect, try another orderer, compare chain hashes at a common height\n    }\n}","preventionTips":["Seed lastBlockHeaderHash from a trusted source (your own ledger, not the remote orderer).","Prefer connecting via multiple orderers and cross-check hashes at a common height.","Never ignore hash-chain mismatches; they indicate forks or tampering.","Keep genesis/config block verification enabled so clients detect divergent networks early."],"tags":["fabric","deliver-client","hash-chain","block-verification","chain-integrity"],"backgroundTag":"block-hash-chain-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"}