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
- Verify the buffer contents: print Header.Number of all blocks and identify the gap or duplicate.
- 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).
- Ensure blocks are appended to the buffer strictly in sequence order; sort or re-request missing sequences before verifying.
- If the local ledger has gaps, resync from genesis or from the latest config block pulled from the ordering service.
- 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
- Only append blocks to the buffer in strictly increasing sequence order
- Re-request missing sequences instead of skipping over gaps
- Do not mix blocks from multiple orderers/sources in one buffer without validation
- Monitor puller logs for skipped or retried sequence numbers
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
- previous block header is nil
- got unexpected status: %v -- %s
- node id mismatch
- channel %s doesn't exist
- block [%d]'s hash (%s) mismatches block [%d]'s prev block ha
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/f45baf681feaadfd.
Report an issue: GitHub.