hyperledger/fabric · error
previous block header is nil
Error message
previous block header is nil
What it means
VerifyBlockHash in orderer/common/cluster/util.go checks hash-chain continuity between consecutive blocks in a block buffer. This error is returned when the block at indexInBuffer-1 (the previous block) has a nil Header field, making it impossible to compare sequence numbers or compute the previous block's hash. The library throws it to fail fast on a malformed/partially initialized block rather than panic on a nil pointer dereference.
Source
Thrown at orderer/common/cluster/util.go:246
}
seq := block.Header.Number
dataHash, err := protoutil.BlockDataHash(block.Data)
if err != nil {
return err
}
// Verify data hash matches the hash in the header
if !bytes.Equal(dataHash, block.Header.DataHash) {
computedHash := hex.EncodeToString(dataHash)
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)View on GitHub (pinned to 2736b63f8f)
Solutions
- Inspect the previous block in the buffer and verify it was fully unmarshaled (proto.Unmarshal of common.Block succeeded and Header != nil).
- Fix the producer code path that constructs/pulls blocks so it never appends blocks with nil headers; discard malformed blocks before buffering.
- If blocks come from BlockPuller, re-pull the block from another orderer node as the local copy is corrupt.
- Check for SDK/proto version mismatches between the component producing blocks and cluster.Util.
- Add a defensive check of prevBlock.Header != nil before calling VerifyBlockHash.
Example fix
// before
blockBuff := []*common.Block{&common.Block{Data: data}, block}
err := cluster.VerifyBlockHash(1, blockBuff) // error: previous block header is nil
// after
var prev, curr common.Block
proto.Unmarshal(prevBytes, &prev)
proto.Unmarshal(currBytes, &curr)
if prev.Header == nil { return errors.New("previous block is malformed, refusing to verify") }
err := cluster.VerifyBlockHash(1, []*common.Block{&prev, &curr}) Defensive patterns
Strategy: validation
Validate before calling
func canVerify(idx int, buff []*common.Block) bool {
return idx > 0 && idx < len(buff) && buff[idx].Header != nil && buff[idx-1].Header != nil
}
if !canVerify(1, blockBuff) { return errors.New("malformed block buffer: missing header") }
err := cluster.VerifyBlockHash(1, blockBuff) Type guard
func hasHeader(b *common.Block) bool { return b != nil && b.Header != nil }
// guard: if !hasHeader(blockBuff[i-1]) { skip/repull block } Try / catch
if err := cluster.VerifyBlockHash(idx, blockBuff); err != nil {
if strings.Contains(err.Error(), "previous block header is nil") {
// drop/re-pull the malformed block at idx-1 from another orderer
}
return err
} Prevention
- Always fully proto.Unmarshal blocks before adding them to a buffer
- Discard (and re-pull) any block with nil Header/Data instead of buffering it
- Never construct common.Block fixtures with only partial fields set
- Keep Fabric proto libraries version-aligned across components
When it happens
Trigger: Calling cluster.VerifyBlockHash(indexInBuffer, blockBuff) where blockBuff[indexInBuffer-1].Header is nil — i.e., a block earlier in the buffer was constructed without a header (e.g., a truncated or improperly deserialized *common.Block).
Common situations: Blocks pulled over the network and deserialized incompletely; test fixtures that populate block data but not the header; memory corruption or protocol-version mismatch where a zero-value common.Block enters the buffer.
Related errors
- sequences %d and %d were received consecutively
- got unexpected status: %v -- %s
- node id mismatch
- channel %s doesn't exist
- block [%d]'s hash (%s) mismatches block [%d]'s prev block ha
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/0e6ee037d938bf7b.
Report an issue: GitHub.