{"record":{"id":"7e3fde5a74545a74","repo":"dgraph-io/badger","slug":"committs-cannot-be-zero-please-use-commitat-inste","errorCode":null,"errorMessage":"CommitTs cannot be zero. Please use commitAt instead","messagePattern":"CommitTs cannot be zero\\. Please use commitAt instead","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"txn.go","lineNumber":626,"sourceCode":"\nfunc (txn *Txn) commitPrecheck() error {\n\tif txn.discarded {\n\t\treturn errors.New(\"Trying to commit a discarded txn\")\n\t}\n\tkeepTogether := true\n\tfor _, e := range txn.pendingWrites {\n\t\tif e.version != 0 {\n\t\t\tkeepTogether = false\n\t\t}\n\t}\n\n\t// If keepTogether is True, it implies transaction markers will be added.\n\t// In that case, commitTs should not be never be zero. This might happen if\n\t// someone uses txn.Commit instead of txn.CommitAt in managed mode.  This\n\t// should happen only in managed mode. In normal mode, keepTogether will\n\t// always be true.\n\tif keepTogether && txn.db.opt.managedTxns && txn.commitTs == 0 {\n\t\treturn errors.New(\"CommitTs cannot be zero. Please use commitAt instead\")\n\t}\n\treturn nil\n}\n\n// Commit commits the transaction, following these steps:\n//\n// 1. If there are no writes, return immediately.\n//\n// 2. Check if read rows were updated since txn started. If so, return ErrConflict.\n//\n// 3. If no conflict, generate a commit timestamp and update written rows' commit ts.\n//\n// 4. Batch up all writes, write them to value log and LSM tree.\n//\n// 5. If callback is provided, Badger will return immediately after checking\n// for conflicts. Writes to the database will happen in the background.  If\n// there is a conflict, an error will be returned and the callback will not\n// run. If there are no conflicts, the callback will be called in the","sourceCodeStart":608,"sourceCodeEnd":644,"githubUrl":"https://github.com/dgraph-io/badger/blob/2a001d466f6b71a917319a1db41f99860e16e269/txn.go#L608-L644","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before (managed mode)\ntxn := db.NewTransactionAt(readTs, true)\ntxn.Set(key, val)\ntxn.Commit()\n// after\ntxn := db.NewTransactionAt(readTs, true)\ntxn.Set(key, val)\ncommitTs := getNextTs() // nonzero, monotonic\ntxn.CommitAt(commitTs, nil)","handlingStrategy":"validation","validationCode":"// in managed mode, before committing:\nif commitTs == 0 {\n    return errors.New(\"managed txns require a nonzero commit timestamp; use CommitAt\")\n}\ntxn.CommitAt(commitTs, nil)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["badger","managed-mode","commit-timestamp","transaction"],"backgroundTag":"commit-timestamp-zero","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"}