dgraph-io/badger · error

ReadTs should not be retrieved for managed DB

Error message

ReadTs should not be retrieved for managed DB

What it means

This is a panic thrown by the oracle's readTs() when the DB is running with managed transactions enabled. In managed mode, read timestamps are supplied by the caller (via db.NewTransactionAt(ts, ...)), so fetching one internally via newTransaction is forbidden. The panic fires immediately before readTs would be computed.

Source

Thrown at txn.go:80

		//
		// WaterMarks must be 64-bit aligned for atomic package, hence we must use pointers here.
		// See https://golang.org/pkg/sync/atomic/#pkg-note-BUG.
		readMark: &y.WaterMark{Name: "badger.PendingReads"},
		txnMark:  &y.WaterMark{Name: "badger.TxnTimestamp"},
		closer:   z.NewCloser(2),
	}
	orc.readMark.Init(orc.closer)
	orc.txnMark.Init(orc.closer)
	return orc
}

func (o *oracle) Stop() {
	o.closer.SignalAndWait()
}

func (o *oracle) readTs() uint64 {
	if o.isManaged {
		panic("ReadTs should not be retrieved for managed DB")
	}

	var readTs uint64
	o.Lock()
	readTs = o.nextTxnTs - 1
	o.readMark.Begin(readTs)
	o.Unlock()

	// Wait for all txns which have no conflicts, have been assigned a commit
	// timestamp and are going through the write to value log and LSM tree
	// process. Not waiting here could mean that some txns which have been
	// committed would not be read.
	y.Check(o.txnMark.WaitForMark(context.Background(), readTs))
	return readTs
}

func (o *oracle) nextTs() uint64 {
	o.Lock()

View on GitHub (pinned to 2a001d466f)

Solutions

  1. Replace db.NewTransaction/View/Update with db.NewTransactionAt(readTs, update) in managed mode, passing an appropriate read timestamp
  2. Obtain valid timestamps via db.Sequence-free APIs like the commit callbacks or an external allocator (e.g. Badger's oracle / watermarks)
  3. If managed mode is not needed, open the DB without WithManagedTxns(true)
  4. Audit all transaction-creation call sites (grep for NewTransaction/View/Update) when enabling managed txns

Example fix

// before (managed DB)
txn := db.NewTransaction(true)
// after (managed DB)
readTs := getReadTs() // from your timestamp allocator
if readTs == 0 {
    db.View(func(txn *badger.Txn) error { ... }) // not allowed in managed mode
}
txn := db.NewTransactionAt(readTs, true)
Defensive patterns

Strategy: validation

Validate before calling

if db.Opts().ManagedTxns { // must use NewTransactionAt
    txn := db.NewTransactionAt(readTs, true)
} else {
    txn := db.NewTransaction(true)
}

Prevention

When it happens

Trigger: Calling db.NewTransaction(update=true) (or View/Update helpers) on a DB opened with WithManagedTxns(true); only db.NewTransactionAt(ts, update) and db.NewWriteBatchAt are valid transaction sources in managed mode.

Common situations: Enabling managed mode for Dgraph or custom timestamp control while leaving existing View()/Update() calls in place; library code (ORM layers, caches) that assumes standard transaction creation; toggling managedTxns in config without auditing all transaction creation sites.

Related errors


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