vectordotdev/vector · error
interval_ms validated to fit in i64 in Aggregate::new
Error message
interval_ms validated to fit in i64 in Aggregate::new
What it means
`bucket_key` converts the configured `interval_ms` (u64) to i64 with `try_from` and expects success, relying on validation in `Aggregate::new`. A value above `i64::MAX` panics here. The conversion must be i64 because `div_euclid` operates on i64 timestamps.
Solutions
- Use a realistic `interval_ms` (millisecond-scale window sizes)
- Ensure `Aggregate::new` validates `interval_ms` fits in i64 and rejects the config otherwise
- Run `vector validate` before deployment
- File a bug if a reasonable interval triggers the panic
Defensive patterns
Strategy: validation
Validate before calling
if cfg.interval_ms > i64::MAX as u64 {
return Err("interval_ms too large".into());
} Prevention
- Use realistic window intervals (seconds/minutes)
- Validate interval fits i64 during config load
- Add unit tests for extreme interval values
- Run `vector validate` before deployment
When it happens
Trigger: An Aggregate whose `interval_ms` exceeds `i64::MAX` reaches `bucket_key` (via `record_event_time`) without constructor validation.
Common situations: Absurdly large interval values in config on versions/forks lacking constructor validation; direct unit-test construction of Aggregate with unvalidated config.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- allowed_lateness_ms validated to fit in i64 in…
- max_future_ms validated to fit in i64 in Aggregate::new
- event-time path requires AggregateConfig.event_time
- output for default port required for task transforms
- a record with a next ID must have an event count
AI-assisted analysis of vectordotdev/vector@bdb87aeaa4 (2026-09-16).
Data as JSON: /api/errors/02bdf386c6d46edd.
Report an issue: GitHub.
Appendix: source
Thrown at src/transforms/aggregate/event_time.rs:118
"only storable metrics reach event-time bucketing"
);
self.record_into_bucket(bucket_key, series, data, metadata);
emit!(AggregateEventRecorded);
None
}
/// Start of the half-open window `[bucket_key, bucket_key + interval_ms)` containing
/// `timestamp`, aligned to multiples of `interval_ms` from the Unix epoch.
///
/// Euclidean division (`div_euclid`) is required: Rust's truncating `/`
/// rounds toward zero, so timestamps just before the epoch (negative
/// millis) would incorrectly map into the non-negative bucket `[0, interval)`
/// instead of `[-interval, 0)`.
pub(crate) fn bucket_key(&self, timestamp: DateTime<Utc>) -> BucketKey {
let timestamp_ms = timestamp.timestamp_millis();
// Range-validated in `Aggregate::new` to fit in i64.
let interval_ms = i64::try_from(self.config.interval_ms)
.expect("interval_ms validated to fit in i64 in Aggregate::new");
timestamp_ms
.div_euclid(interval_ms)
.saturating_mul(interval_ms)
}
/// Returns `true` if `bucket_key` belongs to a window that has already
/// been emitted and therefore must not accept any further events.
///
/// `watermark` is the *exclusive end* of the highest bucket flushed so
/// far -- equivalently, the smallest `bucket_key` that is still valid to
/// record into. `allowed_lateness_ms` is honoured at flush time (it
/// delays closing the bucket); once a window has been emitted it is
/// closed unconditionally and late events for it are dropped.
const fn was_bucket_flushed(&self, bucket_key: BucketKey) -> bool {
if let Some(watermark) = self.watermark {
bucket_key < watermark
} else {
falseView on GitHub (pinned to bdb87aeaa4)