hyperledger/fabric · error
expected block number=%d, received block number=%d
Error message
expected block number=%d, received block number=%d
What it means
The private data store Commit() checks that the block being committed matches its internal expected block number (nextBlockNum). If the caller supplies a block number that is not exactly the next sequential one, the store rejects it to keep private-data key ordering consistent with the block store. This indicates out-of-order or duplicate block commits reaching the pvtdata store.
Source
Thrown at core/ledger/pvtdatastorage/store.go:316
s.isLastUpdatedOldBlocksSet = true
} // false if not set
return nil
}
// Init initializes the store. This function is expected to be invoked before using the store
func (s *Store) Init(btlPolicy pvtdatapolicy.BTLPolicy) {
s.btlPolicy = btlPolicy
}
// Commit commits the pvt data as well as both the eligible and ineligible
// missing private data --- `eligible` denotes that the missing private data belongs to a collection
// for which this peer is a member; `ineligible` denotes that the missing private data belong to a
// collection for which this peer is not a member.
func (s *Store) Commit(blockNum uint64, pvtData []*ledger.TxPvtData, missingPvtData ledger.TxMissingPvtData, purgeMarkers []*PurgeMarker) error {
expectedBlockNum := s.nextBlockNum()
if expectedBlockNum != blockNum {
return errors.Errorf("expected block number=%d, received block number=%d", expectedBlockNum, blockNum)
}
batch := s.db.NewUpdateBatch()
var err error
var key, val []byte
storeEntries, err := prepareStoreEntries(blockNum, pvtData, s.btlPolicy, missingPvtData, purgeMarkers)
if err != nil {
return err
}
for _, dataEntry := range storeEntries.dataEntries {
key = encodeDataKey(dataEntry.key)
if val, err = encodeDataValue(dataEntry.value); err != nil {
return err
}
batch.Put(key, val)
}View on GitHub (pinned to 2736b63f8f)
Solutions
- Verify blocks are committed strictly in sequence; check the caller (commitToPvtAndBlockStore) is not skipping or duplicating block numbers.
- If the stores diverged, reset both the block store and pvtdata store to the same height (e.g. peer node reset/rollback to a common block).
- Check for stale backups: restore block store and pvtdata store snapshots taken at the same block height.
- Inspect logs for the expected vs received numbers to determine which store is ahead/behind and resync accordingly.
Example fix
// before pvtdataStore.Commit(ledger.NextBlockNumber(currentBlockNum)+1, pvtData, missing, purgeMarkers) // after pvtdataStore.Commit(nextExpectedBlockNum, pvtData, missing, purgeMarkers) // must equal store.nextBlockNum()
Defensive patterns
Strategy: validation
Validate before calling
if blockNum != expectedNextBlockNum(store) {
return fmt.Errorf("refusing commit: block %d out of sequence, expected %d", blockNum, expectedNextBlockNum(store))
}
err := store.Commit(blockNum, pvtData, missing, purgeMarkers) Try / catch
if err := store.Commit(blockNum, pvtData, missing, purgeMarkers); err != nil {
if strings.Contains(err.Error(), "expected block number") {
// sequence divergence: halt commit pipeline, run ledger reset/rollback to resync
}
return err
} Prevention
- Commit blocks strictly sequentially through a single commit path/goroutine.
- After any peer reset or rollback, reset both block store and pvtdata store to the same height.
- Monitor expected vs received block numbers in logs to catch divergence early.
When it happens
Trigger: Calling Store.Commit(blockNum, ...) with a blockNum != s.nextBlockNum() — e.g. committing block N+1 before N, re-committing an already-committed block, or resetting one store but not the other so the sequences diverge.
Common situations: Ledger rollback/reset applied to the block store but not the private data store (or vice versa); custom ledger implementations committing out of order; concurrent/gossip-driven commit races; restoring from a backup that is offset by one or more blocks.
Related errors
- block number should have been %d but was %d
- unable to check whether collection existed earlier for chain
- the store is empty
- last committed block number [%d] smaller than the requested
- unexpected call. Boot KV Hashes are persisted only for the d
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/20cf6aae4edc81db.
Report an issue: GitHub.