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
- Use a realistic Year step (e.g. 1-1000 years) in the bar spec.
- Validate that now_year + step stays within jiff's supported range before registering the timer.
- Bound step so step <= ~9000 to guarantee the walk stays in range.
- 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
- Keep Year steps small enough that current_year + step stays within jiff's range.
- Validate at config load: reject Year bars with step > ~9000.
- Prefer Day/Month aggregation for very long periods.
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
- DurationNanos overflow in from_millis
- DurationNanos overflow in from_secs
- DurationNanos overflow in from_mins
- DurationNanos overflow in from_hours
- DurationNanos overflow in from_days
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/2bee8ba79fbff2cf.
Report an issue: GitHub.