dgraph-io/dgraph · error

Transaction is too old

Error message

Transaction is too old

What it means

ErrTsTooOld is returned when a mutation arrives with a start timestamp older than the current watermark/commit state, meaning the transaction is so old its mutations can no longer be safely applied in the MVCC ordering. The transaction must be aborted and retried with a fresh timestamp.

Source

Thrown at posting/mvcc.go:62

	priorityKeys []*pooledKeys
	count        uint64

	// Get Timestamp function gets a new timestamp to store the rollup at. This makes sure that
	// we are not overwriting any transaction. If there are transactions that are ongoing,
	// which modify the item, rollup wouldn't affect the data, as a delta would be written
	// later on
	getNewTs func(bool) uint64
	closer   *z.Closer
}

type CachePL struct {
	list       *List
	lastUpdate uint64
}

var (
	// ErrTsTooOld is returned when a transaction is too old to be applied.
	ErrTsTooOld = errors.Errorf("Transaction is too old")
	// ErrInvalidKey is returned when trying to read a posting list using
	// an invalid key (e.g the key to a single part of a larger multi-part list).
	ErrInvalidKey = errors.Errorf("cannot read posting list using multi-part list key")
	// ErrHighPriorityOp is returned when rollup is cancelled so that operations could start.
	ErrHighPriorityOp = errors.New("Cancelled rollup to make way for high priority operation")

	// IncrRollup is used to batch keys for rollup incrementally.
	IncrRollup = &incrRollupi{
		priorityKeys: make([]*pooledKeys, 2),
	}
)

var MemLayerInstance *MemoryLayer

func init() {
	x.AssertTrue(len(IncrRollup.priorityKeys) == 2)
	for i := range IncrRollup.priorityKeys {
		IncrRollup.priorityKeys[i] = &pooledKeys{

View on GitHub (pinned to 759e242be6)

Solutions

  1. Abort the transaction and retry it with a new timestamp (client retry loop)
  2. Keep transactions short-lived; avoid holding mutations open during slow app logic
  3. Reduce write contention causing mutation queues to back up past the watermark
  4. Verify Alpha timestamps/watermarks are advancing normally (no stalled oracle)

Example fix

// before
err := dgraphMutate(ctx, txn) // txn started long ago
// after: retry on ErrTsTooOld
err := dgraphMutate(ctx, txn)
if errors.Is(err, posting.ErrTsTooOld) {
    txn = startFreshTxn(ctx)
    err = dgraphMutate(ctx, txn)
}
Defensive patterns

Strategy: retry

Validate before calling

// Before mutating, ensure the txn's startTs is still valid (app-level check)
if time.Since(txnStartedAt) > maxTxnAge {
    txn = restartTxn(ctx) // abort and start a fresh transaction
}

Try / catch

err := runMutation(ctx, txn)
if errors.Is(err, posting.ErrTsTooOld) {
    txn.Discard()
    txn = dgraph.NewTxn(ctx)
    err = runMutation(ctx, txn) // retry with fresh timestamp
}

Prevention

When it happens

Trigger: addMutationHelper / addReverseMutationHelper receive a txn whose startTs is less than or equal to a committed watermark (e.g. after the txn was delayed in a queue, or a client held a read-only/low-timestamp transaction too long while writes committed).

Common situations: Long-lived transactions held open by a client for minutes/hours while other writers commit; heavy write load starving a queued transaction; clock/timestamp skew after cluster membership or snapshot changes.

Related errors


AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01). Data as JSON: /api/errors/fd63f1da6e92f3de. Report an issue: GitHub.