{"record":{"id":"417a6690327acdcd","repo":"vitessio/vitess","slug":"bug-cannot-add-record-because-it-does-not-start-a","errorCode":null,"errorMessage":"BUG: cannot add record because it does not start at the beginning of the interval. record: %v","messagePattern":"BUG: cannot add record because it does not start at the beginning of the interval\\. record: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/throttler/interval_history.go","lineNumber":54,"sourceCode":"\tnextIntervalStart time.Time\n}\n\nfunc newIntervalHistory(capacity int64, interval time.Duration) *intervalHistory {\n\treturn &intervalHistory{\n\t\trecords:  make([]record, 0, capacity),\n\t\tinterval: interval,\n\t}\n}\n\n// add\n// It is up to the programmer to ensure that two add() calls do not cover the\n// same interval.\nfunc (h *intervalHistory) add(record record) {\n\tif record.time.Before(h.nextIntervalStart) {\n\t\tpanic(fmt.Sprintf(\"BUG: cannot add record because it is already covered by a previous entry. record: %v next expected interval start: %v\", record, h.nextIntervalStart))\n\t}\n\tif !record.time.Truncate(h.interval).Equal(record.time) {\n\t\tpanic(fmt.Sprintf(\"BUG: cannot add record because it does not start at the beginning of the interval. record: %v\", record))\n\t}\n\t// TODO(mberlin): Bound the list.\n\th.records = append(h.records, record)\n\th.nextIntervalStart = record.time.Add(h.interval)\n}\n\n// average returns the average value across all observations which span\n// the range [from, to).\n// Partially included observations are accounted by their included fraction.\n// Missing observations are assumed with the value zero.\nfunc (h *intervalHistory) average(from, to time.Time) float64 {\n\t// Search only entries whose time of observation is in [start, end).\n\t// Example: [from, to) = [1.5s, 2.5s) => [start, end) = [1s, 2s)\n\tstart := from.Truncate(h.interval)\n\tend := to.Truncate(h.interval)\n\n\tsum := 0.0\n\tcount := 0.0","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/throttler/interval_history.go#L36-L72","documentation":"intervalHistory.add requires each record's time to fall exactly on an interval boundary (time truncated by the interval must equal itself). Records that start mid-interval would corrupt the fixed-width bucketing, so add panics with this BUG message. It is a programmer-contract violation within the throttler.","triggerScenarios":"Calling add with a record whose time is not aligned to the interval grid (e.g. interval = 1s but record.time = 12:00:00.250).","commonSituations":"Test code constructing record times without truncating to the interval; a producer passing raw measurement timestamps instead of interval-start-aligned timestamps; changes to the interval duration that silently break previously-aligned timestamps.","solutions":["Align the record time before calling add: record.time = rawTime.Truncate(h.interval).","In tests, build timestamps as base.Add(n * h.interval) from a truncated base so they land on boundaries.","Verify the interval passed to newIntervalHistory matches the granularity of the timestamps you feed it."],"exampleFix":"// before\nh.add(record{time: time.Now(), lag: lag}) // mid-interval time panics\n// after\nh.add(record{time: time.Now().Truncate(h.interval), lag: lag})","handlingStrategy":"validation","validationCode":"func isAligned(t time.Time, interval time.Duration) bool {\n  return t.Truncate(interval).Equal(t)\n}\n// only call h.add when isAligned(t, h.interval)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Truncate raw measurement timestamps to the interval before adding","Keep the interval duration fixed for the lifetime of the history","Build test timestamps via base.Add(n * interval) from a truncated base"],"tags":["go","panic","throttler","time-series","invariant-violation"],"backgroundTag":"unaligned-interval-timestamp","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}