hyperledger/fabric · critical

block [%d]'s hash (%s) mismatches block [%d]'s prev block ha

Error message

block [%d]'s hash (%s) mismatches block [%d]'s prev block hash (%s)

What it means

VerifyBlockHash verifies the hash linkage of the chain: each block's Header.PreviousHash must equal the SHA-256 hash of the previous block's header (protoutil.BlockHeaderHash). This error is returned when the current block claims a previous-hash that does not match the hash actually computed from the previous buffered block, meaning the two blocks do not belong to the same hash chain. This is the core tamper/fork detection of the replication path.

Source

Thrown at orderer/common/cluster/util.go:255

		claimedHash := hex.EncodeToString(block.Header.DataHash)
		return errors.Errorf("computed hash of block (%d) (%s) doesn't match claimed hash (%s)",
			seq, computedHash, claimedHash)
	}
	// We have a previous block in the buffer, ensure current block's previous hash matches the previous one.
	if indexInBuffer > 0 {
		prevBlock := blockBuff[indexInBuffer-1]
		currSeq := block.Header.Number
		if prevBlock.Header == nil {
			return errors.New("previous block header is nil")
		}
		prevSeq := prevBlock.Header.Number
		if prevSeq+1 != currSeq {
			return errors.Errorf("sequences %d and %d were received consecutively", prevSeq, currSeq)
		}
		if !bytes.Equal(block.Header.PreviousHash, protoutil.BlockHeaderHash(prevBlock.Header)) {
			claimedPrevHash := hex.EncodeToString(block.Header.PreviousHash)
			actualPrevHash := hex.EncodeToString(protoutil.BlockHeaderHash(prevBlock.Header))
			return errors.Errorf("block [%d]'s hash (%s) mismatches block [%d]'s prev block hash (%s)",
				prevSeq, actualPrevHash, currSeq, claimedPrevHash)
		}
	}
	return nil
}

// VerifyBlockSignature verifies the signature on the block with the given BlockVerifier and the given config.
func VerifyBlockSignature(block *common.Block, verifier protoutil.BlockVerifierFunc) error {
	return verifier(block.Header, block.Metadata)
}

// EndpointCriteria defines criteria of how to connect to a remote orderer node.
type EndpointCriteria struct {
	Endpoint   string   // Endpoint of the form host:port
	TLSRootCAs [][]byte // PEM encoded TLS root CA certificates
}

// String returns a string representation of this EndpointCriteria

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Compare the hex hashes in the error against a known-good orderer's ledger to identify which block diverged.
  2. Re-pull the divergent block (and subsequent blocks) from a trusted orderer via BlockPuller and overwrite the local copies.
  3. If the local ledger is corrupted, stop the node and resync the chain (restore from backup taken at a consistent height or re-join the channel).
  4. Verify all orderers run the same Fabric version and belong to the same consenter set; a fork indicates a TLS/endpoint configuration pulling from the wrong cluster.
  5. Never manually edit or copy individual block files into the ledger directory.

Example fix

// before
buffer := []*common.Block{blockFromOrdererA, blockFromOrdererB} // different forks
err := cluster.VerifyBlockHash(1, buffer) // hash mismatch
// after
buffer := []*common.Block{blockFromOrdererA}
next, err := trustedPuller.PullBlock(blockFromOrdererA.Header.Number + 1) // same trusted source
buffer = append(buffer, next)
err = cluster.VerifyBlockHash(1, buffer)
Defensive patterns

Strategy: validation

Validate before calling

func hashChainValid(buff []*common.Block) bool {
    for i := 1; i < len(buff); i++ {
        if !bytes.Equal(buff[i].Header.PreviousHash, protoutil.BlockHeaderHash(buff[i-1].Header)) {
            return false
        }
    }
    return true
}
if !hashChainValid(blockBuff) { return errors.New("pulled blocks do not form a hash chain; refusing to apply") }

Type guard

func blockLinksTo(prev, curr *common.Block) bool {
    return prev.Header != nil && curr.Header != nil &&
        bytes.Equal(curr.Header.PreviousHash, protoutil.BlockHeaderHash(prev.Header))
}

Try / catch

if err := cluster.VerifyBlockHash(idx, blockBuff); err != nil {
    if strings.Contains(err.Error(), "mismatches block") {
        // treat as integrity violation: halt, alert, re-pull from a trusted orderer
        return ErrLedgerIntegrity
    }
    return err
}

Prevention

When it happens

Trigger: Calling cluster.VerifyBlockHash(indexInBuffer, blockBuff) where bytes.Equal(block.Header.PreviousHash, protoutil.BlockHeaderHash(prevBlock.Header)) is false — the PreviousHash field of the current block disagrees with the computed hash of the preceding block.

Common situations: Blocks pulled from a Byzantine or forked orderer; a ledger directory that mixes blocks from different chains/forks (e.g., after a manual copy or a restore from a mismatched backup); a different network/channel's block injected into the buffer; corrupted storage flipping bytes in a header.

Related errors


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