hyperledger/fabric · error

expected metadata in block to be [view_id:%d latest_sequence

Error message

expected metadata in block to be [view_id:%d latest_sequence:%d] but got [view_id:%d latest_sequence:%d]

What it means

In Hyperledger Fabric's SmartBFT ordering consensus, the proposer places SmartBFT ViewMetadata (view_id, latest_sequence) both in the proposal and in the block's orderer metadata. During VerifyProposal, verifyBlockDataAndMetadata unmarshals the metadata from the proposal and proto-Compares it with the metadata embedded in the block. This error means the two copies disagree, so the block header's metadata was tampered with or produced by a node on a different view/sequence than the proposal.

Source

Thrown at orderer/consensus/smartbft/verifier.go:295

	ordererMetadataFromSignature := &cb.OrdererBlockMetadata{}
	if err := proto.Unmarshal(signatureMetadata.Value, ordererMetadataFromSignature); err != nil {
		return nil, errors.Wrap(err, "failed unmarshaling OrdererBlockMetadata")
	}

	// Ensure the view metadata in the block signature and in the proposal are the same

	metadataInBlock := &smartbftprotos.ViewMetadata{}
	if err := proto.Unmarshal(ordererMetadataFromSignature.ConsenterMetadata, metadataInBlock); err != nil {
		return nil, errors.Wrap(err, "failed unmarshaling smartbft metadata from block")
	}

	metadataFromProposal := &smartbftprotos.ViewMetadata{}
	if err := proto.Unmarshal(metadata, metadataFromProposal); err != nil {
		return nil, errors.Wrap(err, "failed unmarshaling smartbft metadata from proposal")
	}

	if !proto.Equal(metadataInBlock, metadataFromProposal) {
		return nil, errors.Errorf(
			"expected metadata in block to be [view_id:%d latest_sequence:%d] but got [view_id:%d latest_sequence:%d]",
			metadataFromProposal.GetViewId(), metadataFromProposal.GetLatestSequence(),
			metadataInBlock.GetViewId(), metadataInBlock.GetLatestSequence(),
		)
	}

	rtc := v.RuntimeConfig.Load().(RuntimeConfig)
	lastConfig := rtc.LastConfigBlock.Header.Number

	if protoutil.IsConfigBlock(block) {
		lastConfig = block.Header.Number
	}

	// Verify last config
	if ordererMetadataFromSignature.LastConfig == nil {
		return nil, errors.Errorf("last config is nil")
	}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Confirm all consenters run the same Fabric version (SmartBFT metadata format changed across releases) and upgrade stragglers.
  2. Restart the ordering service so the node re-enters the current view and regenerates consistent proposal metadata.
  3. If a leader repeatedly produces this mismatch, force a view change (leader timeout/election) to elect a healthy leader.
  4. Check on-disk ledger integrity of the block metadata; restore the node from a snapshot/backup if corruption is suspected.
  5. Compare ViewId/LatestSequence in the log message to determine whether the divergence is a view change (view_id) or sequence lag (latest_sequence) and fix accordingly (stale leader vs. slow node).

Example fix

// before (stale leader proposal metadata after view change)
metadataFromProposal: {ViewId: 3, LatestSequence: 120}
metadataInBlock:      {ViewId: 4, LatestSequence: 120}  -> error
// after: force leader re-proposal in the current view so both carry ViewId 4
metadataFromProposal: {ViewId: 4, LatestSequence: 120}
metadataInBlock:      {ViewId: 4, LatestSequence: 120}
Defensive patterns

Strategy: validation

Validate before calling

md := &common.ViewMetadata{}
if err := proto.Unmarshal(metadataInBlock, md); err != nil { return err }
if md.GetViewId() != currentView || md.GetLatestSequence() != currentSeq {
    return fmt.Errorf("block metadata view/seq %d/%d != current %d/%d", md.GetViewId(), md.GetLatestSequence(), currentView, currentSeq)
}

Try / catch

result, err := verifier.VerifyProposal(prop)
if err != nil {
    if strings.Contains(err.Error(), "expected metadata in block") {
        // force view change / re-sync before retrying
    }
    return err
}

Prevention

When it happens

Trigger: VerifyProposal -> verifyBlockDataAndMetadata: proto.Equal(metadataInBlock, metadataFromProposal) is false, i.e. the ViewMetadata in the block (from the signature/verification path) has a different ViewId or LatestSequence than the metadata attached to the proposal being verified. Also triggered when the proposal's metadata bytes fail to reflect the view change (view_id bump) or sequence advance that the block already carries.

Common situations: A leader assembling a proposal after a view change but reusing stale block metadata; mixed Fabric versions across consenters with different metadata encoding; a corrupted or manually modified block; nodes catching up after a crash so their persisted view_id/latest_sequence diverge from the channel's actual view.

Related errors


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