{"record":{"id":"1c6ba38ea9206821","repo":"hyperledger/fabric","slug":"nil-value-not-allowed","errorCode":null,"errorMessage":"Nil value not allowed","messagePattern":"Nil value not allowed","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/ledger/util/leveldbhelper/leveldb_provider.go","lineNumber":322,"sourceCode":"\n// Close closes the DBHandle after its db data have been deleted\nfunc (h *DBHandle) Close() {\n\tif h.closeFunc != nil {\n\t\th.closeFunc()\n\t}\n}\n\n// UpdateBatch encloses the details of multiple `updates`\ntype UpdateBatch struct {\n\tleveldbBatch *leveldb.Batch\n\tdbName       string\n\tsize         int\n}\n\n// Put adds a KV\nfunc (b *UpdateBatch) Put(key []byte, value []byte) {\n\tif value == nil {\n\t\tpanic(\"Nil value not allowed\")\n\t}\n\tk := constructLevelKey(b.dbName, key)\n\tb.leveldbBatch.Put(k, value)\n\tb.size += len(k) + len(value)\n}\n\n// Delete deletes a Key and associated value\nfunc (b *UpdateBatch) Delete(key []byte) {\n\tk := constructLevelKey(b.dbName, key)\n\tb.size += len(k)\n\tb.leveldbBatch.Delete(k)\n}\n\n// Size returns the current size of the batch\nfunc (b *UpdateBatch) Size() int {\n\treturn b.size\n}\n","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/common/ledger/util/leveldbhelper/leveldb_provider.go#L304-L340","documentation":"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.","triggerScenarios":"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{}.","commonSituations":"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.","solutions":["Replace nil with an empty slice: put(key, []byte{}) when a nil-value delete/tombstone is intended","Fix upstream code so values are never nil on the success path — check errors before Put","Add a caller-side nil check before invoking Put to fail gracefully instead of panicking"],"exampleFix":"// before\nbatch.Put(key, value) // panics when value == nil\n// after\nif value == nil {\n\tvalue = []byte{}\n}\nbatch.Put(key, value)","handlingStrategy":"validation","validationCode":"func safePut(b *leveldbhelper.UpdateBatch, key, value []byte) error {\n\tif value == nil { return errors.New(\"value must not be nil; use []byte{} for empty\") }\n\tb.Put(key, value)\n\treturn nil\n}","typeGuard":"func isPuttable(value []byte) bool { return value != nil }","tryCatchPattern":"func() {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tif s, ok := r.(string); ok && s == \"Nil value not allowed\" {\n\t\t\t\tlog.Error(\"nil value passed to UpdateBatch.Put — use []byte{} instead\")\n\t\t\t}\n\t\t}\n\t}()\n\tbatch.Put(key, value)\n}()","preventionTips":["Always use []byte{} instead of nil for empty values","Check errors from value-producing helpers before passing results to Put","Guard map lookups: if v, ok := m[k]; ok { batch.Put(k, v) }","Wrap Put calls in a helper that asserts non-nil values"],"tags":["leveldb","panic","validation","update-batch"],"backgroundTag":"nil-value-not-allowed","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}