hyperledger/fabric · critical
block header previous hash mismatch on sequence %d, expected
Error message
block header previous hash mismatch on sequence %d, expected %x, got %x
What it means
The follower pulled block `seq` from the ordering service and found its Header.PreviousHash does not equal the hash of the preceding block it verified. This is a hash-chain break between consecutively pulled blocks, so the follower refuses to append and returns ErrRetryCountExhausted-wrapped error. It protects against appending a block from a forked or tampered chain.
Source
Thrown at orderer/common/follower/follower_chain.go:541
actualPrevHash = protoutil.BlockHeaderHash(prevBlock.Header)
}
// Pull until the latest height
for seq := firstBlockToPull; seq < targetHeight; seq++ {
n := seq - firstBlockToPull
select {
case <-c.stopChan:
c.logger.Debug("Received a stop signal")
return n, ErrChainStopped
default:
nextBlock := c.blockPuller.PullBlock(seq)
if nextBlock == nil {
return n, errors.WithMessagef(cluster.ErrRetryCountExhausted, "failed to pull block %d", seq)
}
reportedPrevHash := nextBlock.Header.PreviousHash
if (nextBlock.Header.Number > 0) && !bytes.Equal(reportedPrevHash, actualPrevHash) {
return n, errors.Errorf("block header previous hash mismatch on sequence %d, expected %x, got %x",
nextBlock.Header.Number, actualPrevHash, reportedPrevHash)
}
if c.joinBlock != nil && c.joinBlock.Header.Number == nextBlock.Header.Number {
// We don't need to verify the block.Data because we verify the join-block's DataHash against the
// hash(join-block.Data) when we verify it during the `Join` REST API call
if !proto.Equal(nextBlock.Header, c.joinBlock.Header) {
c.logger.Errorf("Block header mismatch between the block we pulled and the block we joined with, sequence %d", c.joinBlock.Header.Number)
return n, errors.Errorf("block header mismatch between the block we pulled and the block we joined with, sequence %d", c.joinBlock.Header.Number)
}
}
actualPrevHash = protoutil.BlockHeaderHash(nextBlock.Header)
if err := c.ledgerResources.Append(nextBlock); err != nil {
return n, errors.WithMessagef(err, "failed to append block %d to the ledger", nextBlock.Header.Number)
}
if protoutil.IsConfigBlock(nextBlock) {View on GitHub (pinned to 2736b63f8f)
Solutions
- Verify the follower is connected to the correct, trusted ordering endpoints (orderer endpoint list / cluster root CAs in the join request) and the intended channel.
- Compare the offending block against other orderers' blocks; if forks are detected, investigate the consensus/raft state of the ordering service.
- Re-join the follower with a clean ledger and correct join block so verification restarts from a known-good genesis/config block.
- Enable TLS with proper root CAs to eliminate block corruption/MITM in transit, then retry pullUntilLatestWithRetry.
Defensive patterns
Strategy: try-catch
Try / catch
if err := pullUntilLatestWithRetry(...); err != nil { if strings.Contains(err.Error(), "previous hash mismatch") { quarantine follower; investigate ordering service fork } } Prevention
- Always use TLS with pinned cluster root CAs to the ordering service
- Point followers only at official ordering endpoints for the channel
- Monitor ordering service for raft/fork indicators
- Re-join from a clean ledger after any re-genesis
When it happens
Trigger: pullUntilTarget pulls consecutive blocks and nextBlock.Header.Number > 0 with bytes.Equal(reportedPrevHash, actualPrevHash) false — the ordering service served a block whose PreviousHash does not match the previously appended block's hash (fork, tampering, or serving blocks from a different channel/consensus history).
Common situations: A malicious or misconfigured ordering node serving blocks from a divergent fork; a follower connected to the wrong ordering endpoint/channel; block bytes corrupted in transit without TLS/integrity protection; mixing snapshots from different network generations.
Related errors
- cannot enable channel capabilities without orderer support f
- Must set some OrdererAddresses
- chaincode %s attempted to write to the namespace of LSCC
- proposal hash does not match
- client claimed TLS hash doesn't match computed TLS hash from
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/264409032800c714.
Report an issue: GitHub.