nautechsystems/nautilus_trader · error
Invalid bar interval
Error message
Invalid bar interval
What it means
`get_bar_interval_ns` (crates/model/src/data/bar.rs:203) converts the `SignedDuration` returned by `get_bar_interval` into a `DurationNanos` with `try_from(...).expect("Invalid bar interval")`. The conversion fails when the interval is negative or its total nanoseconds exceed what DurationNanos (i64 nanoseconds, ~292 years) can hold, causing this panic.
Source
Thrown at crates/model/src/data/bar.rs:203
// Proxy for comparing bar lengths
duration_days(step.checked_mul(30).expect("`step` overflows i64 days"))
}
BarAggregation::Year => {
// Proxy for comparing bar lengths
duration_days(step.checked_mul(365).expect("`step` overflows i64 days"))
}
_ => panic!("Aggregation not time based"),
}
}
/// Returns the bar interval as [`DurationNanos`].
///
/// # Panics
///
/// Panics if the aggregation method of the given `bar_type` is not time based.
#[must_use]
pub fn get_bar_interval_ns(bar_type: &BarType) -> DurationNanos {
DurationNanos::try_from(get_bar_interval(bar_type)).expect("Invalid bar interval")
}
/// Returns the time bar start as a timezone-aware `Timestamp`.
///
/// # Panics
///
/// Panics if computing the base civil date or datetime from `now` fails,
/// if `step` cannot be represented for the calendar arithmetic,
/// or if the aggregation type is unsupported.
#[must_use]
pub fn get_time_bar_start(
now: Timestamp,
bar_type: &BarType,
time_bars_origin: Option<SignedDuration>,
) -> Timestamp {
let spec = bar_type.spec();
let step = step_to_i64(spec.step);
let origin_offset = time_bars_origin.unwrap_or(SignedDuration::ZERO);View on GitHub (pinned to 18893faf8b)
Solutions
- Reduce the bar step/aggregation so the total interval is under ~292 years (i64 nanoseconds).
- If you need longer intervals, avoid get_bar_interval_ns and work with the SignedDuration from get_bar_interval directly.
- Validate the step at BarType construction so the resulting interval fits i64 nanoseconds.
Example fix
// before
let ns = get_bar_interval_ns(&bar_type); // panics for huge steps
// after
let interval = get_bar_interval(&bar_type);
assert!(interval.is_positive());
let ns = DurationNanos::try_from(interval).unwrap_or_else(|_| {
// handle oversized interval explicitly
...
}); Defensive patterns
Strategy: validation
Validate before calling
// rust
fn interval_fits_nanos(bar_type: &BarType) -> bool {
let d = get_bar_interval(bar_type);
d.is_positive() && DurationNanos::try_from(d).is_ok()
} Try / catch
// Prefer explicit handling over the internal expect:
let interval = get_bar_interval(&bar_type);
let ns = DurationNanos::try_from(interval)
.map_err(|_| BarConfigError::IntervalTooLarge)?; Prevention
- Keep bar intervals under i64 nanoseconds (~292 years).
- Use get_bar_interval (SignedDuration) when you need very long intervals.
- Validate steps when building BarTypes from untrusted config.
When it happens
Trigger: Calling `get_bar_interval_ns` with a time-based `BarType` whose interval converts to a duration that cannot fit into i64 nanoseconds (e.g. enormous Day/Week/Month/Year steps), or otherwise an interval the try_from rejects.
Common situations: Aggregating with a very large step so the interval exceeds i64 nanoseconds; the test `test_time_bar_aggregator_accepts_interval_above_i64_nanos` shows larger intervals are tolerated elsewhere but not representable as DurationNanos here.
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
- DurationNanos overflow in from_micros
- {e}
- vega pricing timeout exceeds the nanosecond range
- `step` exceeds i64 range
- `deltas` instrument IDs must match `instrument_id` {instrume
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/224b26199b3f1809.
Report an issue: GitHub.