hyperledger/fabric · error
invalid block, header must be different from nil, channel=%s
Error message
invalid block, header must be different from nil, channel=%s
What it means
BlockVerificationAssistant.verifyHeader rejects a delivered block whose Header field is nil. The deliver client verifies each block from the ordering service before handing it up, and a block without a header cannot be numbered, hash-chained, or validated, so it is refused immediately with the channel name included.
Source
Thrown at common/deliverclient/block_verification.go:316
func (a *BlockVerificationAssistant) UpdateBlockHeader(block *common.Block) {
a.lastBlockHeader = block.Header
a.lastBlockHeaderHash = protoutil.BlockHeaderHash(block.Header)
}
func (a *BlockVerificationAssistant) verifyMetadata(block *common.Block) error {
if block.Metadata == nil || len(block.Metadata.Metadata) < len(common.BlockMetadataIndex_name) {
return errors.Errorf("block with id [%d] on channel [%s] does not have metadata or contains too few entries", block.Header.Number, a.channelID)
}
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
- Inspect the block received from the deliver stream and check why Header is unpopulated before it reaches VerifyBlock.
- Verify the ordering service node is healthy and emitting well-formed blocks (compare against peers' blocks).
- If the caller constructs the block, populate block.Header (Number, PreviousHash, DataHash) before calling VerifyBlock.
- Add a nil/field check on block.Header at the call site to fail fast with a clearer local error.
Example fix
// before
blk := &common.Block{Data: data}
assistant.VerifyBlock(blk)
// after
if blk.Header == nil {
return fmt.Errorf("refusing to verify block with nil header")
}
blk.Header = &common.BlockHeader{Number: n, PreviousHash: prev, DataHash: hash}
assistant.VerifyBlock(blk) Defensive patterns
Strategy: validation
Validate before calling
if blk == nil || blk.Header == nil {
return fmt.Errorf("block or block.Header is nil; not calling VerifyBlock")
} Type guard
func hasHeader(b *common.Block) bool { return b != nil && b.Header != nil } Try / catch
err := assistant.VerifyBlock(blk)
if err != nil && strings.Contains(err.Error(), "header must be different from nil") {
// malformed block from stream: log, drop block, and re-sync from a trusted height
} Prevention
- Always validate protobuf-decoded blocks for non-nil Header before verification.
- Monitor ordering node health to catch nodes emitting malformed blocks.
- In tests, use realistic block builders (protoutil) rather than hand-built structs.
When it happens
Trigger: VerifyBlock or VerifyBlockAttestation is called with a *common.Block that has Header == nil — i.e. a nil-adjacent/empty or malformed block envelope arrived from the deliver stream (or a caller constructed a block programmatically without populating Header).
Common situations: Corrupt or truncated gRPC deliver payloads; a misbehaving or buggy ordering node emitting empty blocks; unit/integration tests passing partially initialized common.Block structs; custom marshaling/deserialization bugs in code that builds blocks from protobuf payloads.
Related errors
- expected block number is [%d] but actual block number inside
- Header.PreviousHash of block [%d] is different from Hash(blo
- last block header hash is missing
- no endpoints
- could not create a signed Deliver SeekInfo message, somethin
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/cd3cc2c98c23cde0.
Report an issue: GitHub.