{"record":{"id":"0f1f3b8b0048f6a1","repo":"dgraph-io/badger","slug":"opt-prefix-should-be-nil-for-newkeyiterator","errorCode":null,"errorMessage":"opt.Prefix should be nil for NewKeyIterator.","messagePattern":"opt\\.Prefix should be nil for NewKeyIterator\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"iterator.go","lineNumber":498,"sourceCode":"\tfor i := 0; i < len(tables); i++ {\n\t\titers = append(iters, tables[i].sl.NewUniIterator(opt.Reverse))\n\t}\n\titers = txn.db.lc.appendIterators(iters, &opt) // This will increment references.\n\tres := &Iterator{\n\t\ttxn:    txn,\n\t\tiitr:   table.NewMergeIterator(iters, opt.Reverse),\n\t\topt:    opt,\n\t\treadTs: txn.readTs,\n\t}\n\treturn res\n}\n\n// NewKeyIterator is just like NewIterator, but allows the user to iterate over all versions of a\n// single key. Internally, it sets the Prefix option in provided opt, and uses that prefix to\n// additionally run bloom filter lookups before picking tables from the LSM tree.\nfunc (txn *Txn) NewKeyIterator(key []byte, opt IteratorOptions) *Iterator {\n\tif len(opt.Prefix) > 0 {\n\t\tpanic(\"opt.Prefix should be nil for NewKeyIterator.\")\n\t}\n\topt.Prefix = key // This key must be without the timestamp.\n\topt.prefixIsKey = true\n\topt.AllVersions = true\n\treturn txn.NewIterator(opt)\n}\n\nfunc (it *Iterator) newItem() *Item {\n\titem := it.waste.pop()\n\tif item == nil {\n\t\titem = &Item{slice: new(y.Slice), txn: it.txn}\n\t}\n\treturn item\n}\n\n// Item returns pointer to the current key-value pair.\n// This item is only valid until it.Next() gets called.\nfunc (it *Iterator) Item() *Item {","sourceCodeStart":480,"sourceCodeEnd":516,"githubUrl":"https://github.com/dgraph-io/badger/blob/2a001d466f6b71a917319a1db41f99860e16e269/iterator.go#L480-L516","documentation":"NewKeyIterator iterates all versions of a single key by setting opt.Prefix itself from the key argument. Because Prefix is owned by NewKeyIterator, supplying your own non-empty opt.Prefix is ambiguous and Badger panics to prevent silent misconfiguration.","triggerScenarios":"Calling txn.NewKeyIterator(key, opt) where opt was previously used with NewIterator and still carries a Prefix (or was explicitly configured with SetPrefix).","commonSituations":"Reusing a shared IteratorOptions struct across iterator types; copying iterator config from a prefix-scan helper into a key-version lookup.","solutions":["Clear the prefix before calling: opt.Prefix = nil (or build a fresh IteratorOptions)","Use iterator_options_t.ReuseIteratorOptions-style reset or construct opt inline per call","Use txn.NewIterator(opt) instead if you actually want a manual prefix scan"],"exampleFix":"// before\nopt.Prefix = []byte(\"user:\")\nit := txn.NewKeyIterator(key, opt) // panics\n// after\nopt.Prefix = nil\nit := txn.NewKeyIterator(key, opt)","handlingStrategy":"validation","validationCode":"if len(opt.Prefix) > 0 { opt.Prefix = nil } // before NewKeyIterator\nit := txn.NewKeyIterator(key, opt)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Construct a fresh IteratorOptions per iterator call instead of sharing","Clear Prefix when switching from NewIterator to NewKeyIterator","Remember NewKeyIterator sets Prefix from the key argument itself"],"tags":["panic","iterator","options-validation","prefix"],"backgroundTag":"invalid-iterator-options","analyzedSha":"2a001d466f6b71a917319a1db41f99860e16e269","analyzedAt":"2026-09-05T13:00:02.264Z","contentChangedAt":"2026-09-05T13:00:02.264Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}