{"record":{"id":"ad54510930534995","repo":"vitessio/vitess","slug":"interval-too-small-ad5451","errorCode":null,"errorMessage":"interval too small","messagePattern":"interval too small","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/stats/rates.go","lineNumber":80,"sourceCode":"\t// It's used to calculate the latest total rate.\n\tpreviousTotalCount int64\n\t// timestampLastSampling is the time the periodic sampling was run last.\n\ttimestampLastSampling time.Time\n\t// totalRate is the rate of total counts per second seen in the latest\n\t// sampling interval e.g. 100 queries / 5 seconds sampling interval = 20 QPS.\n\ttotalRate float64\n\tctx       context.Context\n\tcancel    context.CancelFunc\n}\n\n// NewRates reports rolling rate information for countTracker. samples specifies\n// the number of samples to report, and interval specifies the time interval\n// between samples. The minimum interval is 1 second.\n// If passing the special value of -1s as interval, we don't snapshot.\n// (use this for tests).\nfunc NewRates(name string, countTracker CountTracker, samples int, interval time.Duration) *Rates {\n\tif interval < 1*time.Second && interval != -1*time.Second {\n\t\tpanic(\"interval too small\")\n\t}\n\tctx, cancel := context.WithCancel(context.Background())\n\trt := &Rates{\n\t\ttimeStamps:            NewRingInt64(samples + 1),\n\t\tcounts:                make(map[string]*RingInt64),\n\t\tcountTracker:          countTracker,\n\t\tsamples:               samples + 1,\n\t\tinterval:              interval,\n\t\ttimestampLastSampling: timeNow(),\n\t\tctx:                   ctx,\n\t\tcancel:                cancel,\n\t}\n\tif name != \"\" {\n\t\tpublish(name, rt)\n\t}\n\tif interval > 0 {\n\t\tgo rt.track()\n\t}","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/stats/rates.go#L62-L98","documentation":"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.","triggerScenarios":"Calling stats.NewRates(name, tracker, samples, d) with d == 0 or 0 < d < 1s, e.g. NewRates(\"qps\", ct, 10, 500*time.Millisecond).","commonSituations":"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.","solutions":["Pass an interval >= 1*time.Second to NewRates.","Use -1*time.Second if you intentionally want no snapshotting (tests).","If sub-second rates are needed, sample the counter yourself and compute the rate externally — this API's floor is 1s."],"exampleFix":"// before\nrt := stats.NewRates(\"qps\", ct, 10, 500*time.Millisecond) // panics\n// after\nrt := stats.NewRates(\"qps\", ct, 10, 1*time.Second)","handlingStrategy":"validation","validationCode":"const minInterval = 1 * time.Second\nif interval != -1*time.Second && interval < minInterval {\n    interval = minInterval\n}\nrt := stats.NewRates(name, tracker, samples, interval)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use named duration constants >= 1s for rate sampling.","Never pass 0 as a 'default' interval; pick a real value or the -1s sentinel.","Review call sites when changing polling cadence constants."],"tags":["go","stats","panic","invalid-interval"],"backgroundTag":"interval-below-minimum","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}