hyperledger/fabric · critical

Header.PreviousHash of block [%d] is different from Hash(blo

Error message

Header.PreviousHash of block [%d] is different from Hash(block.Header) of previous block, on channel [%s], received: %s, expected: %s

What it means

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.

Source

Thrown at common/deliverclient/block_verification.go:326

	return nil
}

func (a *BlockVerificationAssistant) verifyHeader(block *common.Block) error {
	if block == nil {
		return errors.Errorf("block must be different from nil, channel=%s", a.channelID)
	}
	if block.Header == nil {
		return errors.Errorf("invalid block, header must be different from nil, channel=%s", a.channelID)
	}

	expectedBlockNum := a.lastBlockHeader.Number + 1
	if expectedBlockNum != block.Header.Number {
		return errors.Errorf("expected block number is [%d] but actual block number inside block is [%d]", expectedBlockNum, block.Header.Number)
	}

	if len(a.lastBlockHeaderHash) != 0 {
		if !bytes.Equal(block.Header.PreviousHash, a.lastBlockHeaderHash) {
			return errors.Errorf("Header.PreviousHash of block [%d] is different from Hash(block.Header) of previous block, on channel [%s], received: %s, expected: %s",
				block.Header.Number, a.channelID, hex.EncodeToString(block.Header.PreviousHash), hex.EncodeToString(a.lastBlockHeaderHash))
		}
	}
	return nil
}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Verify the ordering node you are connected to is on the same chain as your peers (compare block hashes at a common height).
  2. Reconnect to a different/orderer-consensus-quorum-backed endpoint rather than a possibly forked node.
  3. If the client state is wrong, recompute lastBlockHeaderHash from a trusted local ledger block before resuming the stream.
  4. If a genuine fork/tampering is suspected, halt the client and follow the chain-repair procedures for the network.

Example fix

// before
// blindly resuming stream from a possibly forked orderer
deliverClient.Connect(seekInfoEnv, suspectEndpoint)
// after
if !bytes.Equal(headersAtHeight(orderer, h).Hash(), localLedgerBlockHash(h)) {
    endpoint = selectOrdererOnSameChain(ordererEndpoints, localLedgerBlockHash)
}
deliverClient.Connect(seekInfoEnv, endpoint)
Defensive patterns

Strategy: fallback

Validate before calling

if len(lastBlockHeaderHash) > 0 && !bytes.Equal(blk.Header.PreviousHash, lastBlockHeaderHash) {
    return fmt.Errorf("hash chain broken at block %d; switching orderer", blk.Header.Number)
}

Try / catch

if err := assistant.VerifyBlock(blk); err != nil {
    if strings.Contains(err.Error(), "PreviousHash of block") {
        // treat as possible fork: disconnect, try another orderer, compare chain hashes at a common height
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/24c703822a50693b. Report an issue: GitHub.