dgraph-io/badger · error

Cannot use CommitAt with managedDB=false. Use Commit instead

Error message

Cannot use CommitAt with managedDB=false. Use Commit instead.

What it means

Txn.CommitAt commits a transaction at a caller-specified commit timestamp and therefore requires managed transactions. If the DB was opened without WithManagedTxns(true), the library panics with this message and points you to the ordinary Commit method. The panic occurs before txn.commitTs is set, so nothing is written.

Source

Thrown at managed_db.go:60

	return wb
}
func (db *DB) NewManagedWriteBatch() *WriteBatch {
	if !db.opt.managedTxns {
		panic("cannot use NewManagedWriteBatch with managedDB=false. Use NewWriteBatch instead")
	}

	wb := db.newWriteBatch(true)
	return wb
}

// CommitAt commits the transaction, following the same logic as Commit(), but
// at the given commit timestamp. This will panic if not used with managed transactions.
//
// This is only useful for databases built on top of Badger (like Dgraph), and
// can be ignored by most users.
func (txn *Txn) CommitAt(commitTs uint64, callback func(error)) error {
	if !txn.db.opt.managedTxns {
		panic("Cannot use CommitAt with managedDB=false. Use Commit instead.")
	}
	txn.commitTs = commitTs
	if callback == nil {
		return txn.Commit()
	}
	txn.CommitWith(callback)
	return nil
}

// SetDiscardTs sets a timestamp at or below which, any invalid or deleted
// versions can be discarded from the LSM tree, and thence from the value log to
// reclaim disk space. Can only be used with managed transactions.
func (db *DB) SetDiscardTs(ts uint64) {
	if !db.opt.managedTxns {
		panic("Cannot use SetDiscardTs with managedDB=false.")
	}
	db.orc.setDiscardTs(ts)
}

View on GitHub (pinned to 2a001d466f)

Solutions

  1. Open the DB with WithManagedTxns(true) before creating the txn that you will CommitAt.
  2. Replace txn.CommitAt(ts, cb) with txn.Commit() (and txn.CommitWith(cb) if you need async completion) when not in managed mode.
  3. Move DB opening into a single constructor so managed mode and At-style commit APIs cannot diverge.
  4. If migrating an app to managed mode, update every commit site consistently — mixing Commit and CommitAt on one DB signals a configuration problem.

Example fix

// before
opts := badger.DefaultOptions(dir)
db, _ := badger.Open(opts)
txn := db.NewTransaction(true)
err := txn.CommitAt(200, nil)
// after
opts := badger.DefaultOptions(dir).WithManagedTxns(true)
db, _ := badger.Open(opts)
txn := db.NewTransaction(true)
err := txn.CommitAt(200, nil)
// ...or, without managed mode:
err := txn.Commit()
Defensive patterns

Strategy: try-catch

Validate before calling

if managedMode {
    err := txn.CommitAt(commitTs, cb)
} else {
    if cb != nil {
        txn.CommitWith(cb)
    } else {
        err := txn.Commit()
    }
}

Type guard

func commitAtSupported(managedTxns bool) bool { return managedTxns }

Try / catch

func safeCommitAt(txn *badger.Txn, commitTs uint64, cb func(error)) (err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("CommitAt requires managed mode: %v", r)
        }
    }()
    return txn.CommitAt(commitTs, cb)
}

Prevention

When it happens

Trigger: Calling txn.CommitAt(ts, cb) on a Txn obtained from a DB opened without managed mode; the check happens at the top of CommitAt (managed_db.go:60). Note the callback path: even passing a non-nil callback does not bypass the guard.

Common situations: Code ported from Dgraph or another timestamp-managed layered system; mixing a normal DB handle with CommitAt copied from managed-mode examples; test harnesses that set timestamps manually against default options.

Related errors


AI-assisted analysis of dgraph-io/badger@2a001d466f (2026-09-05). Data as JSON: /api/errors/7f87cb04c724bb05. Report an issue: GitHub.