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

  1. Create a new transaction for each unit of work; never reuse after Commit/Discard
  2. Remove transactions from caches/pools; keep txn lifetime inside one function scope
  3. Do all operations before a deferred txn.Discard() runs
  4. 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

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.