hyperledger/fabric · error

sequences %d and %d were received consecutively

Error message

sequences %d and %d were received consecutively

What it means

VerifyBlockHash enforces that consecutive blocks in the buffer have strictly contiguous sequence numbers: prevBlock.Header.Number + 1 must equal block.Header.Number. This error is returned when blocks N and N+1 positions in the buffer hold sequence numbers that are not consecutive, indicating a gap or a duplicated/out-of-order block. It guards the block replication pipeline against silently accepting a discontinuous chain.

Source

Thrown at orderer/common/cluster/util.go:250

		return err
	}
	// Verify data hash matches the hash in the header
	if !bytes.Equal(dataHash, block.Header.DataHash) {
		computedHash := hex.EncodeToString(dataHash)
		claimedHash := hex.EncodeToString(block.Header.DataHash)
		return errors.Errorf("computed hash of block (%d) (%s) doesn't match claimed hash (%s)",
			seq, computedHash, claimedHash)
	}
	// We have a previous block in the buffer, ensure current block's previous hash matches the previous one.
	if indexInBuffer > 0 {
		prevBlock := blockBuff[indexInBuffer-1]
		currSeq := block.Header.Number
		if prevBlock.Header == nil {
			return errors.New("previous block header is nil")
		}
		prevSeq := prevBlock.Header.Number
		if prevSeq+1 != currSeq {
			return errors.Errorf("sequences %d and %d were received consecutively", prevSeq, currSeq)
		}
		if !bytes.Equal(block.Header.PreviousHash, protoutil.BlockHeaderHash(prevBlock.Header)) {
			claimedPrevHash := hex.EncodeToString(block.Header.PreviousHash)
			actualPrevHash := hex.EncodeToString(protoutil.BlockHeaderHash(prevBlock.Header))
			return errors.Errorf("block [%d]'s hash (%s) mismatches block [%d]'s prev block hash (%s)",
				prevSeq, actualPrevHash, currSeq, claimedPrevHash)
		}
	}
	return nil
}

// VerifyBlockSignature verifies the signature on the block with the given BlockVerifier and the given config.
func VerifyBlockSignature(block *common.Block, verifier protoutil.BlockVerifierFunc) error {
	return verifier(block.Header, block.Metadata)
}

// EndpointCriteria defines criteria of how to connect to a remote orderer node.
type EndpointCriteria struct {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Verify the buffer contents: print Header.Number of all blocks and identify the gap or duplicate.
  2. If blocks were pulled from a peer/orderer, re-pull from a different node whose ledger is known-good (e.g., re-create the BlockPuller with a different endpoint).
  3. Ensure blocks are appended to the buffer strictly in sequence order; sort or re-request missing sequences before verifying.
  4. If the local ledger has gaps, resync from genesis or from the latest config block pulled from the ordering service.
  5. In tests, generate blocks with protoutil utilities that increment Header.Number correctly.

Example fix

// before
buffer := []*common.Block{block5, block7} // gap
err := cluster.VerifyBlockHash(1, buffer) // sequences 5 and 7 were received consecutively
// after
buffer := []*common.Block{block5}
block6, err := puller.PullBlock(6) // fetch the missing block
buffer = append(buffer, block6, block7)
err = cluster.VerifyBlockHash(2, buffer)
Defensive patterns

Strategy: validation

Validate before calling

for i := 1; i < len(blockBuff); i++ {
    if blockBuff[i].Header.Number != blockBuff[i-1].Header.Number+1 {
        return fmt.Errorf("gap between seq %d and %d", blockBuff[i-1].Header.Number, blockBuff[i].Header.Number)
    }
}
err := cluster.VerifyBlockHash(len(blockBuff)-1, blockBuff)

Type guard

func sequencesContiguous(buff []*common.Block) bool {
    for i := 1; i < len(buff); i++ {
        if buff[i].Header == nil || buff[i-1].Header == nil || buff[i].Header.Number != buff[i-1].Header.Number+1 { return false }
    }
    return true
}

Try / catch

if err := cluster.VerifyBlockHash(idx, blockBuff); err != nil {
    var prevSeq, currSeq uint64
    if _, scanErr := fmt.Sscanf(err.Error(), "sequences %d and %d were received consecutively", &prevSeq, &currSeq); scanErr == nil {
        // re-pull block at currSeq from another orderer, then retry verification
    }
    return err
}

Prevention

When it happens

Trigger: Calling cluster.VerifyBlockHash(indexInBuffer, blockBuff) where blockBuff[indexInBuffer-1].Header.Number + 1 != blockBuff[indexInBuffer].Header.Number — e.g., buffer contains blocks with sequences [5, 7] or [5, 5].

Common situations: A BlockPuller pulled blocks from a lagging/misbehaving orderer; an operator manually copied or truncated blocks in the ledger directory; buffers assembled from mixed sources (file + network) resulting in gaps; test code that hand-builds blocks with wrong sequence numbers.

Related errors


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