hyperledger/fabric · error

last committed block number [%d] smaller than the requested

Error message

last committed block number [%d] smaller than the requested block number [%d]

What it means

GetPvtDataByBlockNum rejects queries for blocks beyond the last committed block (atomic.LoadUint64(&s.lastCommittedBlock)). Private data for future blocks cannot exist yet, so the store returns this error instead of empty results. The message includes both the committed height and the requested block.

Source

Thrown at core/ledger/pvtdatastorage/store.go:481

	batch.Delete(lastUpdatedOldBlocksKey)
	if err := s.db.WriteBatch(batch, true); err != nil {
		return err
	}
	s.isLastUpdatedOldBlocksSet = false
	return nil
}

// GetPvtDataByBlockNum returns only the pvt data  corresponding to the given block number
// The pvt data is filtered by the list of 'ns/collections' supplied in the filter
// A nil filter does not filter any results
func (s *Store) GetPvtDataByBlockNum(blockNum uint64, filter ledger.PvtNsCollFilter) ([]*ledger.TxPvtData, error) {
	logger.Debugf("Get private data for block [%d], filter=%#v", blockNum, filter)
	if s.isEmpty {
		return nil, errors.New("the store is empty")
	}
	lastCommittedBlock := atomic.LoadUint64(&s.lastCommittedBlock)
	if blockNum > lastCommittedBlock {
		return nil, errors.Errorf("last committed block number [%d] smaller than the requested block number [%d]", lastCommittedBlock, blockNum)
	}
	startKey, endKey := getDataKeysForRangeScanByBlockNum(blockNum)
	logger.Debugf("Querying private data storage for write sets using startKey=%#v, endKey=%#v", startKey, endKey)
	itr, err := s.db.GetIterator(startKey, endKey)
	if err != nil {
		return nil, err
	}
	defer itr.Release()

	var blockPvtdata []*ledger.TxPvtData
	var currentTxNum uint64
	var currentTxWsetAssember *txPvtdataAssembler
	firstItr := true

	for itr.Next() {
		dataKeyBytes := itr.Key()
		dataValueBytes := itr.Value()
		dataKey, err := decodeDatakey(dataKeyBytes)

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Get the store/ledger height first and only query blocks <= lastCommittedBlock.
  2. If a peer rollback/reset happened, re-query from the new height or resync the peer.
  3. Retry with backoff if the block is expected to arrive shortly (event-driven consumers).
  4. In tests, commit the target block (or seed lastCommittedBlock) before querying.

Example fix

// before
pvt, err := store.GetPvtDataByBlockNum(blockNum, nil)
// after
last := store.LastCommittedBlock()
if blockNum > last {
    return nil, fmt.Errorf("block %d not yet committed (height=%d)", blockNum, last)
}
pvt, err := store.GetPvtDataByBlockNum(blockNum, nil)
Defensive patterns

Strategy: validation

Validate before calling

last := atomic.LoadUint64(&storeLastCommittedBlock) // or query ledger height
if blockNum > last {
    return nil, fmt.Errorf("block %d exceeds committed height %d", blockNum, last)
}
pvt, err := store.GetPvtDataByBlockNum(blockNum, filter)

Try / catch

pvt, err := store.GetPvtDataByBlockNum(blockNum, filter)
if err != nil {
    if strings.Contains(err.Error(), "smaller than the requested block number") {
        // retry with backoff: block may still be in flight
        return retryWithBackoff(func() ([]*ledger.TxPvtData, error) {
            return store.GetPvtDataByBlockNum(blockNum, filter)
        })
    }
    return nil, err
}

Prevention

When it happens

Trigger: Calling GetPvtDataByBlockNum(blockNum, ...) with blockNum > lastCommittedBlock — e.g. querying the block being validated/committed concurrently, or a stale client asking for a future block after a peer reset lowered the height.

Common situations: Clients racing ahead of peer commit during event handling; peer rollback/reset while an upstream service still queries old high block numbers; test harnesses that forget the store height is 0.

Related errors


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