hyperledger/fabric · error

Nil value not allowed. Instead call 'Delete' function

Error message

Nil value not allowed. Instead call 'Delete' function

What it means

UpdateBatch.PutValAndMetadata panics if value is nil. A nil value in an update batch is ambiguous with deletion; the API contract requires explicit Delete calls to remove keys, keeping writes and deletes distinguishable in the redo log and state DB.

Source

Thrown at core/ledger/kvledger/txmgmt/statedb/statedb.go:198

		return nil
	}
	vv, ok := nsUpdates.M[key]
	if !ok {
		return nil
	}
	return vv
}

// Put adds a key with value only. The metadata is assumed to be nil
func (batch *UpdateBatch) Put(ns string, key string, value []byte, version *version.Height) {
	batch.PutValAndMetadata(ns, key, value, nil, version)
}

// PutValAndMetadata adds a key with value and metadata
// TODO introducing a new function to limit the refactoring. Later in a separate CR, the 'Put' function above should be removed
func (batch *UpdateBatch) PutValAndMetadata(ns string, key string, value []byte, metadata []byte, version *version.Height) {
	if value == nil {
		panic("Nil value not allowed. Instead call 'Delete' function")
	}
	batch.Update(ns, key, &VersionedValue{value, metadata, version})
}

// Delete deletes a Key and associated value
func (batch *UpdateBatch) Delete(ns string, key string, version *version.Height) {
	batch.Update(ns, key, &VersionedValue{nil, nil, version})
}

// Exists checks whether the given key exists in the batch
func (batch *UpdateBatch) Exists(ns string, key string) bool {
	nsUpdates, ok := batch.Updates[ns]
	if !ok {
		return false
	}
	_, ok = nsUpdates.M[key]
	return ok
}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Use batch.Delete(ns, key, version) instead when the intent is to remove the key.
  2. Pass an empty non-nil slice ([]byte{}) if an empty value is intended.
  3. Guard the caller: if value == nil, route to Delete before adding to the batch.
  4. Fix the upstream producer (e.g. redo record deserialization) that yielded a nil value.

Example fix

// before
if value == nil { batch.PutValAndMetadata(ns, key, value, md, ver) }
// after
if value == nil {
  batch.Delete(ns, key, ver)
} else {
  batch.PutValAndMetadata(ns, key, value, md, ver)
}
Defensive patterns

Strategy: type-guard

Validate before calling

if value == nil {
  batch.Delete(ns, key, version)
} else {
  batch.PutValAndMetadata(ns, key, value, metadata, version)
}

Type guard

func isWritableValue(v []byte) bool { return v != nil }

Try / catch

// panic-based, so guard before calling:
if value != nil {
  batch.PutValAndMetadata(ns, key, value, metadata, version)
}

Prevention

When it happens

Trigger: Calling PutValAndMetadata (or constructing an UpdateBatch entry via Put) with a nil []byte value during batch assembly — seen in redo-record construction and various statedb/txmgr tests that exercise value+metadata writes.

Common situations: Tooling that mirrors GetState results into a batch where the key was missing (GetState returns nil); code that confuses empty value []byte{} (allowed) with nil (not allowed); redo logger replay of malformed records.

Related errors


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