vitessio/vitess · error

interval too small

Error message

interval too small

What it means

NewRates computes rates from periodic snapshots of a CountTracker, and the snapshot interval must be at least 1 second (with -1s as a test-only sentinel that disables snapshotting). Shorter intervals are rejected with a panic because the rate calculation cannot produce meaningful samples below one second.

Source

Thrown at go/stats/rates.go:80

	// It's used to calculate the latest total rate.
	previousTotalCount int64
	// timestampLastSampling is the time the periodic sampling was run last.
	timestampLastSampling time.Time
	// totalRate is the rate of total counts per second seen in the latest
	// sampling interval e.g. 100 queries / 5 seconds sampling interval = 20 QPS.
	totalRate float64
	ctx       context.Context
	cancel    context.CancelFunc
}

// NewRates reports rolling rate information for countTracker. samples specifies
// the number of samples to report, and interval specifies the time interval
// between samples. The minimum interval is 1 second.
// If passing the special value of -1s as interval, we don't snapshot.
// (use this for tests).
func NewRates(name string, countTracker CountTracker, samples int, interval time.Duration) *Rates {
	if interval < 1*time.Second && interval != -1*time.Second {
		panic("interval too small")
	}
	ctx, cancel := context.WithCancel(context.Background())
	rt := &Rates{
		timeStamps:            NewRingInt64(samples + 1),
		counts:                make(map[string]*RingInt64),
		countTracker:          countTracker,
		samples:               samples + 1,
		interval:              interval,
		timestampLastSampling: timeNow(),
		ctx:                   ctx,
		cancel:                cancel,
	}
	if name != "" {
		publish(name, rt)
	}
	if interval > 0 {
		go rt.track()
	}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Pass an interval >= 1*time.Second to NewRates.
  2. Use -1*time.Second if you intentionally want no snapshotting (tests).
  3. If sub-second rates are needed, sample the counter yourself and compute the rate externally — this API's floor is 1s.

Example fix

// before
rt := stats.NewRates("qps", ct, 10, 500*time.Millisecond) // panics
// after
rt := stats.NewRates("qps", ct, 10, 1*time.Second)
Defensive patterns

Strategy: validation

Validate before calling

const minInterval = 1 * time.Second
if interval != -1*time.Second && interval < minInterval {
    interval = minInterval
}
rt := stats.NewRates(name, tracker, samples, interval)

Prevention

When it happens

Trigger: Calling stats.NewRates(name, tracker, samples, d) with d == 0 or 0 < d < 1s, e.g. NewRates("qps", ct, 10, 500*time.Millisecond).

Common situations: Passing a mis-scaled duration (500 instead of 500*time.Millisecond); reusing an interval constant from a faster polling loop; forgetting that 0 is not a valid 'default' for this API.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/ad54510930534995. Report an issue: GitHub.