hyperledger/fabric · error

block with id [%d] on channel [%s] does not have metadata or

Error message

block with id [%d] on channel [%s] does not have metadata or contains too few entries

What it means

verifyMetadata ensures a delivered block carries block.Metadata with entries for every registered BlockMetadataIndex (SIGNATURES, LAST_CONFIG, TRANSACTIONS_FILTER, ORDERER). A nil Metadata or too-few entries means signature/metadata validation is impossible, so the block is rejected.

Source

Thrown at common/deliverclient/block_verification.go:305

	err := a.sigVerifierFunc(block.Header, block.Metadata)
	if err == nil {
		a.lastBlockHeader = block.Header
		a.lastBlockHeaderHash = protoutil.BlockHeaderHash(block.Header)
	}

	return err
}

// UpdateBlockHeader saves the last block header that was verified and handled successfully.
// This must be called after VerifyBlock and VerifyBlockAttestation and successfully handling the block.
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)
	}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Ensure the block source is a real orderer-produced block containing full Metadata (signature metadata, last-config pointer, tx filter).
  2. Re-fetch the block from a healthy orderer/peer.
  3. Upgrade/align fabric component versions so metadata layouts match.
  4. If generating blocks for tests, populate Metadata with len(common.BlockMetadataIndex_name) entries.

Example fix

// before
block := &common.Block{Header: hdr, Data: data} // Metadata nil

// after
block := &common.Block{Header: hdr, Data: data, Metadata: &common.BlockMetadata{Metadata: [][]byte{sigMeta, lastConfig, txFilter, ordererMeta}}}
Defensive patterns

Strategy: validation

Validate before calling

if block.Metadata == nil || len(block.Metadata.Metadata) < len(common.BlockMetadataIndex_name) {
    return errors.New("block metadata incomplete; refetch from orderer")
}

Type guard

func hasFullMetadata(block *common.Block) bool {
    return block != nil && block.Metadata != nil && len(block.Metadata.Metadata) >= len(common.BlockMetadataIndex_name)
}

Try / catch

if err := bva.VerifyBlock(block, opts); err != nil {
    if strings.Contains(err.Error(), "does not have metadata") {
        block, err = refetchBlock(block.Header.Number)
    }
    return err
}

Prevention

When it happens

Trigger: VerifyBlock or VerifyBlockAttestation receives a block constructed without Metadata (hand-built blocks in tooling/tests), a block produced by an incompatible orderer writing fewer metadata entries, or a block truncated during storage/transfer so Metadata is missing.

Common situations: Custom block generators for tests omitting Metadata; delivering pre-fabric-1.4-style blocks; corrupted block files; cross-version fabric components with differing metadata layouts.

Related errors


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