{"record":{"id":"73ba6012dec9a097","repo":"dgraph-io/badger","slug":"cannot-use-newwritebatch-in-managed-mode-use-neww","errorCode":null,"errorMessage":"cannot use NewWriteBatch in managed mode. Use NewWriteBatchAt instead","messagePattern":"cannot use NewWriteBatch in managed mode\\. Use NewWriteBatchAt instead","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"batch.go","lineNumber":41,"sourceCode":"\tsync.Mutex\n\ttxn      *Txn\n\tdb       *DB\n\tthrottle *y.Throttle\n\terr      atomic.Value\n\n\tisManaged bool\n\tcommitTs  uint64\n\tfinished  bool\n}\n\n// NewWriteBatch creates a new WriteBatch. This provides a way to conveniently do a lot of writes,\n// batching them up as tightly as possible in a single transaction and using callbacks to avoid\n// waiting for them to commit, thus achieving good performance. This API hides away the logic of\n// creating and committing transactions. Due to the nature of SSI guaratees provided by Badger,\n// blind writes can never encounter transaction conflicts (ErrConflict).\nfunc (db *DB) NewWriteBatch() *WriteBatch {\n\tif db.opt.managedTxns {\n\t\tpanic(\"cannot use NewWriteBatch in managed mode. Use NewWriteBatchAt instead\")\n\t}\n\treturn db.newWriteBatch(false)\n}\n\nfunc (db *DB) newWriteBatch(isManaged bool) *WriteBatch {\n\treturn &WriteBatch{\n\t\tdb:        db,\n\t\tisManaged: isManaged,\n\t\ttxn:       db.newTransaction(true, isManaged),\n\t\tthrottle:  y.NewThrottle(16),\n\t}\n}\n\n// SetMaxPendingTxns sets a limit on maximum number of pending transactions while writing batches.\n// This function should be called before using WriteBatch. Default value of MaxPendingTxns is\n// 16 to minimise memory usage.\nfunc (wb *WriteBatch) SetMaxPendingTxns(max int) {\n\twb.throttle = y.NewThrottle(max)","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/dgraph-io/badger/blob/2a001d466f6b71a917319a1db41f99860e16e269/batch.go#L23-L59","documentation":"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.","triggerScenarios":"Calling db.NewWriteBatch() on a DB opened with WithManagedTransactions(true).","commonSituations":"Applications that switched to managed mode for timestamp control (streaming writes, Dgraph) but kept legacy NewWriteBatch call sites.","solutions":["Use db.NewWriteBatchAt(writeTs) instead, passing the managed write timestamp","Call wb.SetEntryAt(e, ts) per entry if per-entry timestamps are needed","Drop WithManagedTransactions(true) from DB options if managed mode is not actually required"],"exampleFix":"// before\nwb := db.NewWriteBatch()\n// after\nwb := db.NewWriteBatchAt(writeTs)\nerr := wb.SetEntryAt(&badger.Entry{Key: key, Value: val}, writeTs)","handlingStrategy":"validation","validationCode":"var wb *badger.WriteBatch\nif managed {\n    wb = db.NewWriteBatchAt(writeTs)\n} else {\n    wb = db.NewWriteBatch()\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Encapsulate WriteBatch creation in one helper aware of managed mode","Audit NewWriteBatch call sites when toggling WithManagedTransactions","Prefer NewWriteBatchAt in any timestamp-controlled pipeline"],"tags":["panic","managed-transactions","write-batch","mode-mismatch"],"backgroundTag":"managed-mode-api-mismatch","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"}