nautechsystems/nautilus_trader · error

Aggregation not time based

Error message

Aggregation not time based

What it means

`get_bar_interval` converts a `BarType`'s specification into a `SignedDuration`. Only time-based aggregations (Millisecond, Second, Minute, Hour, Day, Week, Month, Year) have a duration; the fallthrough `_ => panic!("Aggregation not time based")` fires for non-time aggregations (e.g. Tick, Value/Dollar). The library panics because the function's signature cannot express 'not applicable'.

Source

Thrown at crates/model/src/data/bar.rs:192

    match spec.aggregation {
        BarAggregation::Millisecond => SignedDuration::from_millis(step),
        BarAggregation::Second => SignedDuration::from_secs(step),
        BarAggregation::Minute => SignedDuration::from_mins(step),
        BarAggregation::Hour => SignedDuration::from_hours(step),
        BarAggregation::Day => duration_days(step),
        BarAggregation::Week => {
            duration_days(step.checked_mul(7).expect("`step` overflows i64 days"))
        }
        BarAggregation::Month => {
            // 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,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check `bar_type.spec().aggregation` is a time-based variant before calling `get_bar_interval`.
  2. Restrict the call site to time-based bar types and handle tick/value bars with different logic.
  3. Use the `_checked`/fallible sibling API (`try_time_interval`) instead of the panicking helper if available for your use case.

Example fix

// before
let interval = get_bar_interval(&bar_type); // panics for TICK bars

// after
use BarAggregation::*;
let interval = match bar_type.spec().aggregation {
    Millisecond | Second | Minute | Hour | Day | Week | Month | Year => get_bar_interval(&bar_type),
    _ => return Err(anyhow::anyhow!("non-time bar aggregation")),
};
Defensive patterns

Strategy: validation

Validate before calling

// Rust
fn is_time_based(a: BarAggregation) -> bool {
    use BarAggregation::*;
    matches!(a, Millisecond | Second | Minute | Hour | Day | Week | Month | Year)
}
// call site
debug_assert!(is_time_based(bar_type.spec().aggregation));

Type guard

fn is_time_based(a: BarAggregation) -> bool {
    use BarAggregation::*;
    matches!(a, Millisecond | Second | Minute | Hour | Day | Week | Month | Year)
}

Prevention

When it happens

Trigger: Passing a BarType whose BarSpecification.aggregation is Tick or Value (non-time based) to `get_bar_interval`, directly or indirectly through `get_bar_interval_ns`.

Common situations: Code that computes bar intervals generically over all bar types in a portfolio/config, where some instruments use tick bars or volume/dollar bars; calling interval math in a shared timer routine without filtering aggregation kind.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/5bc361fafe161e57. Report an issue: GitHub.