hyperledger/fabric · warning

Claimed seqNum is [%d] but actual seqNum inside block is [%d

Error message

Claimed seqNum is [%d] but actual seqNum inside block is [%d]

What it means

VerifyBlock confirms that the sequence number claimed by the gossip message matches the actual block number inside the block header. If seqNum != block.Header.Number the block does not correspond to the message, so validation fails with both numbers in the message.

Source

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

	if err != nil {
		mcsLogger.Errorf("Failed computing digest of serialized identity %s: [%s]", peerIdentity, err)
		return nil
	}

	return digest
}

// VerifyBlock returns nil if the block is properly signed, and the claimed seqNum is the
// sequence number that the block's header contains.
// else returns error
func (s *MSPMessageCryptoService) VerifyBlock(chainID common.ChannelID, seqNum uint64, block *pcommon.Block) error {
	if block.Header == nil {
		return fmt.Errorf("Invalid Block on channel [%s]. Header must be different from nil.", chainID)
	}

	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)

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Let gossip discard the stale payload (this error is expected handling for out-of-sync blocks)
  2. If persistent, resync the peer: pull latest blocks from the orderer or a healthy peer
  3. Check for ordering/kafka-raft misconfiguration if many peers report mismatches
Defensive patterns

Strategy: retry

Validate before calling

func seqMatches(b *pcommon.Block, claimed uint64) bool {
    return b != nil && b.Header != nil && b.Header.Number == claimed
}

Type guard

func seqMatches(b *pcommon.Block, claimed uint64) bool {
    return b != nil && b.Header != nil && b.Header.Number == claimed
}

if !seqMatches(block, seqNum) {
    // skip stale payload; gossip will deliver a fresh one
    return nil
}

Try / catch

if err := cryptoService.VerifyBlock(chainID, seqNum, block); err != nil {
    if strings.Contains(err.Error(), "Claimed seqNum") {
        log.Debugf("stale/seq-mismatched block, ignoring: %v", err)
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: Gossip delivery/state-transfer passes a block whose Header.Number differs from the seqNum the peer claims — e.g. stale message replayed after ledger advanced, or mis-indexed block in a pull.

Common situations: Network partitions causing stale gossip payloads; replayed anti-entropy messages; a bug in block puller assigning wrong sequence numbers after a checkpoint/resync.

Related errors


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