hyperledger/fabric · error

Block with id [%d] on channel [%s] does not have metadata. B

Error message

Block with id [%d] on channel [%s] does not have metadata. Block not valid.

What it means

VerifyBlock requires each block to carry metadata (block.Metadata with at least one metadata entry) because signatures and validation info live in the metadata section. A block missing metadata cannot be signed-verified so it is rejected as not valid.

Source

Thrown at internal/peer/gossip/mcs.go:150

	blockSeqNum := block.Header.Number
	if seqNum != blockSeqNum {
		return fmt.Errorf("Claimed seqNum is [%d] but actual seqNum inside block is [%d]", seqNum, blockSeqNum)
	}

	// - Extract channelID and compare with chainID
	channelID, err := protoutil.GetChannelIDFromBlock(block)
	if err != nil {
		return fmt.Errorf("Failed getting channel id from block with id [%d] on channel [%s]: [%s]", block.Header.Number, chainID, err)
	}

	if channelID != string(chainID) {
		return fmt.Errorf("Invalid block's channel id. Expected [%s]. Given [%s]", chainID, channelID)
	}

	// - Unmarshal medatada
	if block.Metadata == nil || len(block.Metadata.Metadata) == 0 {
		return fmt.Errorf("Block with id [%d] on channel [%s] does not have metadata. Block not valid.", block.Header.Number, chainID)
	}

	dataHash, err := protoutil.BlockDataHash(block.Data)
	if err != nil {
		return err
	}
	// - Verify that Header.DataHash is equal to the hash of block.Data
	// This is to ensure that the header is consistent with the data carried by this block
	if !bytes.Equal(dataHash, block.Header.DataHash) {
		return fmt.Errorf("Header.DataHash is different from Hash(block.Data) for block with id [%d] on channel [%s]", block.Header.Number, chainID)
	}

	return s.verifyHeaderAndMetadata(channelID, block)
}

func (s *MSPMessageCryptoService) verifyHeaderAndMetadata(channelID string, block *pcommon.Block) error {
	// Get the policy manager for channelID
	cpm := s.channelPolicyManagerGetter.Manager(channelID)

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Ensure blocks are created/populated via protoutil block-construction helpers that set metadata
  2. Re-fetch the block from the orderer or a committed source instead of the corrupt copy
  3. In tests, populate block.Metadata (e.g. with a valid metadata signature array) before verification

Example fix

// before
block := &common.Block{Header: hdr, Data: data}
// after
block := &common.Block{Header: hdr, Data: data, Metadata: &common.BlockMetadata{
    Metadata: [][]byte{nil, {}, {}},
}}
Defensive patterns

Strategy: type-guard

Validate before calling

func hasMetadata(b *pcommon.Block) bool {
    return b != nil && b.Metadata != nil && len(b.Metadata.Metadata) > 0
}

Type guard

func hasMetadata(b *pcommon.Block) bool {
    return b != nil && b.Metadata != nil && len(b.Metadata.Metadata) > 0
}

if !hasMetadata(block) {
    return errors.New("block missing metadata; cannot verify")
}
err := cryptoService.VerifyBlock(chainID, seqNum, block)

Try / catch

if err := cryptoService.VerifyBlock(chainID, seqNum, block); err != nil {
    if strings.Contains(err.Error(), "does not have metadata") {
        log.Warnf("block %d on %s lacks metadata, rejecting", seqNum, chainID)
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: VerifyBlock called with block.Metadata == nil or block.Metadata.Metadata empty — typically a truncated or hand-constructed block, or a block from which metadata was stripped.

Common situations: Blocks synthesized in unit tests without metadata; corruption during block transfer; code that copies only Header/Data when cloning blocks.

Related errors


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