temporalio/temporal · error

Key encountered positive overflow

Error message

Key encountered positive overflow

What it means

Key.Next computes the lexicographic successor of a task key. When TaskID is MaxInt64 it rolls forward to the next nanosecond with TaskID 0; if FireTime is also at math.MaxInt64 nanoseconds there is no successor and it panics to prevent int64 positive overflow. Called from paths like GetAndCompleteHistoryTask when advancing task keys.

Source

Thrown at service/history/tasks/key.go:84

		return 1
	}
	return 0
}

func (k Key) Prev() Key {
	if k.TaskID == 0 {
		if k.FireTime.UnixNano() == 0 {
			panic("Key encountered negative underflow")
		}
		return NewKey(k.FireTime.Add(-time.Nanosecond), math.MaxInt64)
	}
	return NewKey(k.FireTime, k.TaskID-1)
}

func (k Key) Next() Key {
	if k.TaskID == math.MaxInt64 {
		if k.FireTime.UnixNano() == math.MaxInt64 {
			panic("Key encountered positive overflow")
		}
		return NewKey(k.FireTime.Add(time.Nanosecond), 0)
	}
	return NewKey(k.FireTime, k.TaskID+1)
}

func (k Key) Sub(subtrahend Key) Key {
	borrow := int64(0)
	differenceTaskID := k.TaskID - subtrahend.TaskID
	if differenceTaskID < 0 {
		borrow = 1
		differenceTaskID += MaximumKey.TaskID
	}

	fireTime := k.FireTime.UnixNano() - borrow
	subtrahendFireTime := subtrahend.FireTime.UnixNano()
	if fireTime < subtrahendFireTime {
		panic(fmt.Sprintf("Task key Sub encountered underflow: self: %v, subtrahend: %v", k, subtrahend))

View on GitHub (pinned to bde624efd1)

Solutions

  1. Inspect the offending task's FireTime in persistence; fix the corrupt row or delete/complete it manually.
  2. Guard the caller: check the key against MaximumKey before calling Next().
  3. Trace where the max timestamp was written (often a zero-time or clock misconfiguration serialized as max) and fix the writer.
  4. Add validation when loading tasks so keys near MaximumKey are rejected or repaired at read time.

Example fix

// before
nextKey := task.GetKey().Next()

// after
var nextKey tasks.Key
if task.GetKey() == tasks.MaximumKey {
    return serviceerror.NewInternal("task key at maximum, cannot advance")
}
nextKey = task.GetKey().Next()
Defensive patterns

Strategy: validation

Validate before calling

if k.CompareTo(tasks.MaximumKey) >= 0 {
    return errors.New("task key at maximum, cannot advance")
}

Prevention

When it happens

Trigger: Calling Key.Next() on the maximal key NewKey(time.Unix(0, math.MaxInt64).UTC(), math.MaxInt64); realistically when a task fetched from persistence carries a corrupt/overflowing FireTime and the completion path advances past it.

Common situations: Corrupted persistence rows with sentinel max timestamps; clock/date bugs writing near-max nanosecond timestamps; tests probing boundary keys; retry loops repeatedly calling Next on the same malformed key.

Related errors


AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01). Data as JSON: /api/errors/9ee0635ede0049b2. Report an issue: GitHub.