hyperledger/fabric · error

Nil value not allowed

Error message

Nil value not allowed

What it means

UpdateBatch.Put panics if the value is nil. LevelDB batches cannot carry nil values in this wrapper, and the ledger relies on non-nil (possibly empty) byte slices for tombstones/metadata. Passing nil instead of an empty slice is a programming error and is treated as a hard panic.

Source

Thrown at common/ledger/util/leveldbhelper/leveldb_provider.go:322

// Close closes the DBHandle after its db data have been deleted
func (h *DBHandle) Close() {
	if h.closeFunc != nil {
		h.closeFunc()
	}
}

// UpdateBatch encloses the details of multiple `updates`
type UpdateBatch struct {
	leveldbBatch *leveldb.Batch
	dbName       string
	size         int
}

// Put adds a KV
func (b *UpdateBatch) Put(key []byte, value []byte) {
	if value == nil {
		panic("Nil value not allowed")
	}
	k := constructLevelKey(b.dbName, key)
	b.leveldbBatch.Put(k, value)
	b.size += len(k) + len(value)
}

// Delete deletes a Key and associated value
func (b *UpdateBatch) Delete(key []byte) {
	k := constructLevelKey(b.dbName, key)
	b.size += len(k)
	b.leveldbBatch.Delete(k)
}

// Size returns the current size of the batch
func (b *UpdateBatch) Size() int {
	return b.size
}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Replace nil with an empty slice: put(key, []byte{}) when a nil-value delete/tombstone is intended
  2. Fix upstream code so values are never nil on the success path — check errors before Put
  3. Add a caller-side nil check before invoking Put to fail gracefully instead of panicking

Example fix

// before
batch.Put(key, value) // panics when value == nil
// after
if value == nil {
	value = []byte{}
}
batch.Put(key, value)
Defensive patterns

Strategy: validation

Validate before calling

func safePut(b *leveldbhelper.UpdateBatch, key, value []byte) error {
	if value == nil { return errors.New("value must not be nil; use []byte{} for empty") }
	b.Put(key, value)
	return nil
}

Type guard

func isPuttable(value []byte) bool { return value != nil }

Try / catch

func() {
	defer func() {
		if r := recover(); r != nil {
			if s, ok := r.(string); ok && s == "Nil value not allowed" {
				log.Error("nil value passed to UpdateBatch.Put — use []byte{} instead")
			}
		}
	}()
	batch.Put(key, value)
}()

Prevention

When it happens

Trigger: Calling UpdateBatch.Put(key, nil) — e.g. in add/deleteIndexEntriesRange/ImportFromSnapshot paths when a computed value is nil because an upstream lookup failed or a variable was left uninitialized instead of set to []byte{}.

Common situations: Passing the result of a map lookup (missing key returns nil) straight into Put; returning nil from a serialization helper on error and ignoring the error; refactoring that replaced []byte{} with nil.

Related errors


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