dgraph-io/badger · error
ErrDiscardedTxn
ErrDiscardedTxn
Error message
This transaction has been discarded. Create a new one
What it means
ErrDiscardedTxn indicates a previously discarded (or already committed) transaction is being reused. After txn.Discard() or Commit(), the txn is invalid; Badger returns this from setIdx/modify/Get, and NewIterator panics with it (iterator.go:461).
Source
Thrown at errors.go:37
// ErrValueLogSize is returned when opt.ValueLogFileSize option is not within the valid
// range.
ErrValueLogSize = stderrors.New("Invalid ValueLogFileSize, must be in range [1MB, 2GB)")
// ErrKeyNotFound is returned when key isn't found on a txn.Get.
ErrKeyNotFound = stderrors.New("Key not found")
// ErrTxnTooBig is returned if too many writes are fit into a single transaction.
ErrTxnTooBig = stderrors.New("Txn is too big to fit into one request")
// ErrConflict is returned when a transaction conflicts with another transaction. This can
// happen if the read rows had been updated concurrently by another transaction.
ErrConflict = stderrors.New("Transaction Conflict. Please retry")
// ErrReadOnlyTxn is returned if an update function is called on a read-only transaction.
ErrReadOnlyTxn = stderrors.New("No sets or deletes are allowed in a read-only transaction")
// ErrDiscardedTxn is returned if a previously discarded transaction is reused.
ErrDiscardedTxn = stderrors.New("This transaction has been discarded. Create a new one")
// ErrEmptyKey is returned if an empty key is passed on an update function.
ErrEmptyKey = stderrors.New("Key cannot be empty")
// ErrInvalidKey is returned if the key has a special !badger! prefix,
// reserved for internal usage.
ErrInvalidKey = stderrors.New("Key is using a reserved !badger! prefix")
// ErrBannedKey is returned if the read/write key belongs to any banned namespace.
ErrBannedKey = stderrors.New("Key is using the banned prefix")
// ErrThresholdZero is returned if threshold is set to zero, and value log GC is called.
// In such a case, GC can't be run.
ErrThresholdZero = stderrors.New(
"Value log GC can't run because threshold is set to zero")
// ErrNoRewrite is returned if a call for value log GC doesn't result in a log file rewrite.
ErrNoRewrite = stderrors.New(View on GitHub (pinned to 2a001d466f)
Solutions
- Create a new transaction for each unit of work; never reuse after Commit/Discard
- Remove transactions from caches/pools; keep txn lifetime inside one function scope
- Do all operations before a deferred txn.Discard() runs
- Check errors from Commit — a failed commit also ends the txn's usability
Example fix
// before
txn := db.NewTransaction(true)
txn.Commit()
err := txn.Set([]byte("k"), []byte("v")) // ErrDiscardedTxn
// after
txn := db.NewTransaction(true)
if err := txn.Set([]byte("k"), []byte("v")); err != nil { return err }
return txn.Commit() Defensive patterns
Strategy: validation
Validate before calling
// track txn usability yourself; after Commit/Discard set used=true
if txnDone {
return errors.New("transaction already committed or discarded")
} Try / catch
if err := txn.Get(k); err != nil {
if errors.Is(err, badger.ErrDiscardedTxn) {
txn = db.NewTransaction(true) // recreate and redo the operation
}
return err
} Prevention
- Scope transactions to a single function; create-finish-discard locally
- Never cache Txn objects in structs, pools, or globals
- Remember Commit() also ends the txn — no ops afterwards
When it happens
Trigger: Calling Get/Set/Delete/NewIterator after txn.Commit() or txn.Discard(); reusing a cached/stored transaction across requests; a deferred Discard executing before more operations; callbacks outliving the txn scope.
Common situations: Storing a Txn in a struct or pool and reusing it; forgetting that Commit implicitly discards; goroutines sharing a txn with mismatched lifetimes.
Related errors
AI-assisted analysis of dgraph-io/badger@2a001d466f (2026-09-05).
Data as JSON: /api/errors/f4b57c04814bd662.
Report an issue: GitHub.