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

  1. Inspect the previous block in the buffer and verify it was fully unmarshaled (proto.Unmarshal of common.Block succeeded and Header != nil).
  2. Fix the producer code path that constructs/pulls blocks so it never appends blocks with nil headers; discard malformed blocks before buffering.
  3. If blocks come from BlockPuller, re-pull the block from another orderer node as the local copy is corrupt.
  4. Check for SDK/proto version mismatches between the component producing blocks and cluster.Util.
  5. 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

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


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