dgraph-io/badger · error

cannot use NewWriteBatch in managed mode. Use NewWriteBatchA

Error message

cannot use NewWriteBatch in managed mode. Use NewWriteBatchAt instead

What it means

NewWriteBatch creates a WriteBatch that picks its own commit timestamps. In managed mode timestamps must be supplied by the caller, so Badger forbids NewWriteBatch and requires NewWriteBatchAt(ts) which pins the write version. The panic fires at construction time before any writes are buffered.

Source

Thrown at batch.go:41

	sync.Mutex
	txn      *Txn
	db       *DB
	throttle *y.Throttle
	err      atomic.Value

	isManaged bool
	commitTs  uint64
	finished  bool
}

// NewWriteBatch creates a new WriteBatch. This provides a way to conveniently do a lot of writes,
// batching them up as tightly as possible in a single transaction and using callbacks to avoid
// waiting for them to commit, thus achieving good performance. This API hides away the logic of
// creating and committing transactions. Due to the nature of SSI guaratees provided by Badger,
// blind writes can never encounter transaction conflicts (ErrConflict).
func (db *DB) NewWriteBatch() *WriteBatch {
	if db.opt.managedTxns {
		panic("cannot use NewWriteBatch in managed mode. Use NewWriteBatchAt instead")
	}
	return db.newWriteBatch(false)
}

func (db *DB) newWriteBatch(isManaged bool) *WriteBatch {
	return &WriteBatch{
		db:        db,
		isManaged: isManaged,
		txn:       db.newTransaction(true, isManaged),
		throttle:  y.NewThrottle(16),
	}
}

// SetMaxPendingTxns sets a limit on maximum number of pending transactions while writing batches.
// This function should be called before using WriteBatch. Default value of MaxPendingTxns is
// 16 to minimise memory usage.
func (wb *WriteBatch) SetMaxPendingTxns(max int) {
	wb.throttle = y.NewThrottle(max)

View on GitHub (pinned to 2a001d466f)

Solutions

  1. Use db.NewWriteBatchAt(writeTs) instead, passing the managed write timestamp
  2. Call wb.SetEntryAt(e, ts) per entry if per-entry timestamps are needed
  3. Drop WithManagedTransactions(true) from DB options if managed mode is not actually required

Example fix

// before
wb := db.NewWriteBatch()
// after
wb := db.NewWriteBatchAt(writeTs)
err := wb.SetEntryAt(&badger.Entry{Key: key, Value: val}, writeTs)
Defensive patterns

Strategy: validation

Validate before calling

var wb *badger.WriteBatch
if managed {
    wb = db.NewWriteBatchAt(writeTs)
} else {
    wb = db.NewWriteBatch()
}

Prevention

When it happens

Trigger: Calling db.NewWriteBatch() on a DB opened with WithManagedTransactions(true).

Common situations: Applications that switched to managed mode for timestamp control (streaming writes, Dgraph) but kept legacy NewWriteBatch call sites.

Related errors


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