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
- Get the store/ledger height first and only query blocks <= lastCommittedBlock.
- If a peer rollback/reset happened, re-query from the new height or resync the peer.
- Retry with backoff if the block is expected to arrive shortly (event-driven consumers).
- 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
- Always derive the max queryable block from ledger/store height, not client assumptions.
- After peer reset/rollback, clamp or recompute stored high-water marks in consumers.
- Use block events to advance your query cursor instead of polling arbitrary heights.
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
- unable to check whether collection existed earlier for chain
- expected block number=%d, received block number=%d
- the store is empty
- unexpected call. Boot KV Hashes are persisted only for the d
- error getting private data by block number %d
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/ad4466db1baa4a0e.
Report an issue: GitHub.