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
- Use batch.Delete(ns, key, version) instead when the intent is to remove the key.
- Pass an empty non-nil slice ([]byte{}) if an empty value is intended.
- Guard the caller: if value == nil, route to Delete before adding to the batch.
- 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
- Remember nil and empty []byte{} are semantically different: nil=delete signal, []byte{}=empty write
- Never feed GetState results directly into Put without a nil check
- Audit batch-building code for paths that propagate nil values
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
- Could not seek block file [%s] to startOffset [%d]. New posi
- Error in decoding varint bytes [%#v]
- error in block index: %s
- Could not retrieve header of the last block form file: %s
- Nil value not allowed
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/702fe09394ab4274.
Report an issue: GitHub.