dgraph-io/badger · error
CommitTs cannot be zero. Please use commitAt instead
Error message
CommitTs cannot be zero. Please use commitAt instead
What it means
In managed-database mode, transactions using write-batching with transaction markers (keepTogether=true) require a nonzero commit timestamp set via txn.CommitAt. This error is returned by commitPrecheck when txn.Commit() is called on a managed transaction whose commitTs is zero, meaning the user called Commit instead of CommitAt. Managed mode gives the caller full control of timestamps, so a zero timestamp is invalid.
Source
Thrown at txn.go:626
func (txn *Txn) commitPrecheck() error {
if txn.discarded {
return errors.New("Trying to commit a discarded txn")
}
keepTogether := true
for _, e := range txn.pendingWrites {
if e.version != 0 {
keepTogether = false
}
}
// If keepTogether is True, it implies transaction markers will be added.
// In that case, commitTs should not be never be zero. This might happen if
// someone uses txn.Commit instead of txn.CommitAt in managed mode. This
// should happen only in managed mode. In normal mode, keepTogether will
// always be true.
if keepTogether && txn.db.opt.managedTxns && txn.commitTs == 0 {
return errors.New("CommitTs cannot be zero. Please use commitAt instead")
}
return nil
}
// Commit commits the transaction, following these steps:
//
// 1. If there are no writes, return immediately.
//
// 2. Check if read rows were updated since txn started. If so, return ErrConflict.
//
// 3. If no conflict, generate a commit timestamp and update written rows' commit ts.
//
// 4. Batch up all writes, write them to value log and LSM tree.
//
// 5. If callback is provided, Badger will return immediately after checking
// for conflicts. Writes to the database will happen in the background. If
// there is a conflict, an error will be returned and the callback will not
// run. If there are no conflicts, the callback will be called in theView on GitHub (pinned to 2a001d466f)
Solutions
- Use txn.CommitAt(ts, nil) instead of txn.Commit() in managed mode, passing a valid nonzero timestamp
- Or set txn.SetCommitTs(ts) before calling CommitWith
- Verify opt.managedTxns is intentional; if you don't need timestamp control, disable managed mode and use Commit() normally
- Ensure the commit timestamp comes from a monotonic source (e.g. db.NewWriteBatchAt or oracle-provided ts), not an uninitialized zero value
Example fix
// before (managed mode) txn := db.NewTransactionAt(readTs, true) txn.Set(key, val) txn.Commit() // after txn := db.NewTransactionAt(readTs, true) txn.Set(key, val) commitTs := getNextTs() // nonzero, monotonic txn.CommitAt(commitTs, nil)
Defensive patterns
Strategy: validation
Validate before calling
// in managed mode, before committing:
if commitTs == 0 {
return errors.New("managed txns require a nonzero commit timestamp; use CommitAt")
}
txn.CommitAt(commitTs, nil) Prevention
- In managed mode always use CommitAt/SetCommitTs, never Commit
- Derive commitTs from a monotonic allocator, never from a zero-valued variable
- Add a lint/test asserting managed code paths never call txn.Commit
When it happens
Trigger: Calling db.Opts.WithManagedTxns(true) and then using txn.Commit() or CommitWith() without first setting a commit timestamp; the correct call is txn.CommitAt(commitTs, callback) or using db.NewTransactionAt with SetCommitTs. Only occurs when managedTxns is enabled and pendingWrites have version==0 (keepTogether true).
Common situations: Migrating code from normal to managed mode without switching Commit -> CommitAt; Dgraph-style layered usage where the caller forgot to propagate the commit timestamp; forgetting to call txn.SetCommitTs before CommitWith.
Related errors
AI-assisted analysis of dgraph-io/badger@2a001d466f (2026-09-05).
Data as JSON: /api/errors/7e3fde5a74545a74.
Report an issue: GitHub.