hyperledger/fabric · error

index %d out of bounds (total %d blocks)

Error message

index %d out of bounds (total %d blocks)

What it means

VerifyBlockHash was asked to verify the hash chain of a block whose index exceeds the number of blocks actually present in the supplied buffer. The caller passed an indexInBuffer that points past the end of blockBuff, so verification cannot proceed. It is a caller/programming or truncation error, not block corruption.

Source

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

	clientConfigCopy.SecOpts.ServerRootCAs = endpointCriteria.TLSRootCAs

	return clientConfigCopy.Dial(endpointCriteria.Endpoint)
}

// BlockSequenceVerifier verifies that the given consecutive sequence
// of blocks is valid.
type BlockSequenceVerifier func(blocks []*common.Block, channel string) error

// Dialer creates a gRPC connection to a remote address
type Dialer interface {
	Dial(endpointCriteria EndpointCriteria) (*grpc.ClientConn, error)
}

// VerifyBlockHash verifies the hash chain of the block with the given index
// among the blocks of the given block buffer.
func VerifyBlockHash(indexInBuffer int, blockBuff []*common.Block) error {
	if len(blockBuff) <= indexInBuffer {
		return errors.Errorf("index %d out of bounds (total %d blocks)", indexInBuffer, len(blockBuff))
	}
	block := blockBuff[indexInBuffer]
	if block.Header == nil {
		return errors.New("missing block header")
	}
	if block.Data == nil {
		return errors.New("missing block data")
	}
	seq := block.Header.Number
	dataHash, err := protoutil.BlockDataHash(block.Data)
	if err != nil {
		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)",

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Ensure the caller computes indexInBuffer as the block's position within the same buffer it passes (typically the last index: len(blockBuff)-1).
  2. Check upstream code (verifyBlockSequence / BlockPuller) for early returns that shrink blockBuff while continuing to verify at the original index.
  3. If the buffer is genuinely short, re-pull the missing blocks from the source orderer before verifying.

Example fix

// before
err := cluster.VerifyBlockHash(seq, buffer) // seq is chain-height index
// after
if len(buffer) == 0 || seq < buffer[0].Header.Number || int(seq-buffer[0].Header.Number) >= len(buffer) {
    return errors.New("block not present in buffer")
}
err := cluster.VerifyBlockHash(int(seq-buffer[0].Header.Number), buffer)
Defensive patterns

Strategy: validation

Validate before calling

func canVerify(indexInBuffer int, blockBuff []*common.Block) bool {
    return indexInBuffer >= 0 && indexInBuffer < len(blockBuff)
}
if canVerify(idx, buff) {
    err := cluster.VerifyBlockHash(idx, buff)
}

Type guard

func blockAt(buff []*common.Block, i int) (*common.Block, bool) {
    if i < 0 || i >= len(buff) || buff[i] == nil {
        return nil, false
    }
    return buff[i], true
}

Prevention

When it happens

Trigger: Calling VerifyBlockHash(indexInBuffer, blockBuff) where len(blockBuff) <= indexInBuffer — e.g. verifying the last block in a sequence using a buffer that was truncated by an earlier failure or by pull of fewer blocks than expected.

Common situations: Block pulling/replication between Raft orderers where the delivered buffer is shorter than the sequence being verified; off-by-one in caller code computing the index of a block in a partial buffer.

Related errors


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