tsenart/vegeta · error

timeseries: non monotonically increasing timestamp

Error message

timeseries: non monotonically increasing timestamp

What it means

errMonotonicTimestamp is returned by timeSeries.add when a sample's timestamp is smaller than the previously recorded one. The plotting time series requires strictly forward-moving timestamps to keep buckets ordered.

Source

Thrown at lib/plot/timeseries.go:29

// An in-memory timeSeries of points with high compression of
// both timestamps and values.  It's not safe for concurrent use.
type timeSeries struct {
	attack string
	label  string
	prev   uint64
	data   *tsz.Series
	len    int
}

func newTimeSeries(attack, label string) *timeSeries {
	return &timeSeries{
		attack: attack,
		label:  label,
		data:   tsz.New(0),
	}
}

var errMonotonicTimestamp = errors.New("timeseries: non monotonically increasing timestamp")

func (ts *timeSeries) add(t uint64, v float64) error {
	if ts.prev > t {
		return errMonotonicTimestamp
	}

	ts.data.Push(t, v)
	ts.prev = t
	ts.len++

	return nil
}

func (ts *timeSeries) iter() lttb.Iter {
	it := ts.data.Iter()
	return func(count int) ([]lttb.Point, error) {
		ps := make([]lttb.Point, 0, count)
		for i := 0; i < count && it.Next(); i++ {

View on GitHub (pinned to cf58112690)

Solutions

  1. Sort results by timestamp before feeding them into the plot/report builder.
  2. Ensure timestamps come from a single monotonic source (e.g. time.Since(start) rather than wall clock).
  3. If merging series, merge in sorted order or skip/drop out-of-order samples.

Example fix

// before
for _, r := range results { ts.add(uint64(r.Timestamp.UnixNano()), 1) }
// after
sort.Slice(results, func(i, j int) bool { return results[i].Timestamp.Before(results[j].Timestamp) })
for _, r := range results { ts.add(uint64(r.Timestamp.UnixNano()), 1) }
Defensive patterns

Strategy: validation

Validate before calling

sort.Slice(results, func(i, j int) bool {
    return results[i].Timestamp.Before(results[j].Timestamp)
})

Try / catch

if err := ts.add(uint64(r.Timestamp.UnixNano()), v); err != nil {
    log.Printf("skipping out-of-order sample: %v", err)
    continue
}

Prevention

When it happens

Trigger: Calling add(t, v) on lib/plot's timeSeries with t < ts.prev — e.g. replaying out-of-order results or feeding unsorted result slices into the plotting/reporting path.

Common situations: Sorting results by the wrong field, multiple concurrent attackers writing to one time series without ordering, or clock changes producing non-increasing uint64 nanosecond timestamps.

Related errors


AI-assisted analysis of tsenart/vegeta@cf58112690 (2026-08-31). Data as JSON: /api/errors/bfa06b406aa81f18. Report an issue: GitHub.