hyperledger/fabric · error

blockNum should be greater than 0

Error message

blockNum should be greater than 0

What it means

confighistory db's mostRecentEntryBelow requires a block number above 0 because it searches for entries strictly below the given blockNum using blockNum-1 as the start key; blockNum==0 has no lower bound and would produce an invalid iterator range.

Source

Thrown at core/ledger/confighistory/db_helper.go:76

func (p *dbProvider) getDB(id string) *db {
	return &db{p.GetDBHandle(id)}
}

func (b *batch) add(ns, key string, blockNum uint64, value []byte) {
	logger.Debugf("add() - {%s, %s, %d}", ns, key, blockNum)
	k, v := encodeCompositeKey(ns, key, blockNum), value
	b.Put(k, v)
}

func (d *db) writeBatch(batch *batch, sync bool) error {
	return d.WriteBatch(batch.UpdateBatch, sync)
}

func (d *db) mostRecentEntryBelow(blockNum uint64, ns, key string) (*compositeKV, error) {
	logger.Debugf("mostRecentEntryBelow() - {%s, %s, %d}", ns, key, blockNum)
	if blockNum == 0 {
		return nil, errors.New("blockNum should be greater than 0")
	}

	startKey := encodeCompositeKey(ns, key, blockNum-1)
	stopKey := append(encodeCompositeKey(ns, key, 0), byte(0))

	itr, err := d.GetIterator(startKey, stopKey)
	if err != nil {
		return nil, err
	}
	defer itr.Release()
	if !itr.Next() {
		logger.Debugf("Key no entry found. Returning nil")
		return nil, nil
	}
	k, v := decodeCompositeKey(itr.Key()), itr.Value()
	return &compositeKV{k, v}, nil
}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Guard the call site: only query when targetBlockNum > 0, otherwise return a nil config directly
  2. Initialize collection config lookups so block 0 requests short-circuit without hitting the db
  3. Fix off-by-one logic in callers computing blockNum from current height (height 0 means no configs yet)

Example fix

// before
info, _ := mgr.MostRecentCollectionConfigBelow(0, ns, coll)
// after
var info *ledger.CollectionConfigInfo
if blockNum > 0 {
    info, _ = mgr.MostRecentCollectionConfigBelow(blockNum, ns, coll)
}
Defensive patterns

Strategy: validation

Validate before calling

func safeMostRecentConfig(mgr *mgr, blockNum uint64, ns, coll string) (*ledger.CollectionConfigInfo, error) {
    if blockNum == 0 {
        return nil, nil // no config can exist below block 0
    }
    return mgr.MostRecentCollectionConfigBelow(blockNum, ns, coll)
}

Type guard

func blockNumValid(blockNum uint64) bool {
    return blockNum > 0
}

Try / catch

info, err := mgr.MostRecentCollectionConfigBelow(blockNum, ns, coll)
if err != nil {
    if err.Error() == "blockNum should be greater than 0" {
        return nil, nil // treat as "no config below block 0"
    }
    return nil, err
}

Prevention

When it happens

Trigger: MostRecentCollectionConfigBelow (or an anonymous range wrapper) is called with blockNum=0 — i.e. asking for the most recent collection config committed before block 0, which cannot exist.

Common situations: Ledger code computing the config applicable at a block without guarding against block 0; tests or snapshot tooling passing a zero-height block; a ledger queried before any block has been committed.

Related errors


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