nautechsystems/nautilus_trader · error

year exceeds Jiff supported range

Error message

year exceeds Jiff supported range

What it means

Inside the Year branch, each candidate year is narrowed from i32 to i16 because jiff's civil Date only supports years in roughly -9999..9999. When the candidate year leaves that range (after stepping by step_i32), try_from fails and the expect panics. It marks that the year walk ran past the calendar library's supported range.

Source

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

            let months_step =
                u32::try_from(step).expect("`step` exceeds u32 range for month arithmetic");

            while start_time <= now {
                start_time =
                    add_n_months(start_time, months_step).expect("Failed to add months in loop");
            }

            start_time =
                subtract_n_months(start_time, months_step).expect("Failed to subtract months_step");
            start_time
        }
        BarAggregation::Year => {
            let step_i32 =
                i32::try_from(step).expect("`step` exceeds i32 range for year arithmetic");

            // Reconstruct from Jan 1 + origin each time to avoid leap-day drift
            let year_start = |year: i32| {
                let year = i16::try_from(year).expect("year exceeds Jiff supported range");
                Offset::UTC
                    .to_timestamp(
                        Date::new(year, 1, 1)
                            .expect("valid year start date")
                            .at(0, 0, 0, 0),
                    )
                    .expect("valid UTC year start")
                    + origin_offset
            };

            let mut year = i32::from(Offset::UTC.to_datetime(now).year());
            if year_start(year) > now {
                year = year
                    .checked_sub(step_i32)
                    .expect("year arithmetic underflow");
            }

            loop {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Use a realistic Year step (e.g. 1-1000 years) in the bar spec.
  2. Validate that now_year + step stays within jiff's supported range before registering the timer.
  3. Bound step so step <= ~9000 to guarantee the walk stays in range.
  4. Switch aggregation (Day/Month) if an enormous period is intended.

Example fix

// before
BarType::from_spec(2_000_000_000, BarAggregation::Year)
// after
assert!(step > 0 && step <= 9_000);
BarType::from_spec(step, BarAggregation::Year)
Defensive patterns

Strategy: validation

Validate before calling

let now_year = Offset::UTC.to_datetime(now).year();
if now_year.abs() + step > 9_000 {
    return Err(format!("year step {step} pushes beyond supported calendar range"));
}

Type guard

fn year_step_in_range(now_year: i16, step: i64) -> bool {
    (now_year as i64).abs() + step <= 9_000
}

Try / catch

let start = std::panic::catch_unwind(|| get_time_bar_start(now, &bar_type, origin))
    .map_err(|_| anyhow::anyhow!("year walk exceeded jiff supported range"))?;

Prevention

When it happens

Trigger: get_time_bar_start with a Year bar where year ± step_i32 walks beyond jiff's supported year range — e.g. current year plus a step like 2_000_000_000, or checked_add accumulating past i16 bounds before the break condition is met.

Common situations: Absurdly large Year steps from misconfigured specs; unchecked programmatic BarType construction; tests probing range limits.

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


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