nautechsystems/nautilus_trader · error
year arithmetic underflow
Error message
year arithmetic underflow
What it means
When the origin-adjusted Jan-1 anchor is after `now`, the current year is decremented by step_i32 using checked_sub; if that would underflow i32 (only possible with a negative or huge step combined with boundary years), the expect panics. It guards the backward year walk.
Source
Thrown at crates/model/src/data/bar.rs:306
// 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 {
let next_year = year
.checked_add(step_i32)
.expect("year arithmetic overflow");
if year_start(next_year) > now {
break;
}
year = next_year;
}
year_start(year)
}
_ => panic!(
"Aggregation type {} not supported for time bars",
spec.aggregationView on GitHub (pinned to 18893faf8b)
Solutions
- Use a sane positive Year step; validate step bounds before constructing the BarType.
- Ensure `now` yields a normal UTC year (e.g. within 1900-2200).
- Reject bar specs whose step magnitude makes year ± step exceed i32 at config validation.
- File an issue if reproducible with realistic inputs.
Example fix
// before BarType::from_spec(2_147_483_647, BarAggregation::Year) // step near i32::MAX // after assert!(step > 0 && step <= 9_000); BarType::from_spec(step, BarAggregation::Year)
Defensive patterns
Strategy: validation
Validate before calling
let step = step_to_i64(spec.step);
if step <= 0 || step > 9_000 {
return Err(format!("year step {step} out of safe range"));
} Type guard
fn safe_year_step(step: i64) -> bool { step > 0 && step <= 9_000 } Try / catch
let start = std::panic::catch_unwind(|| get_time_bar_start(now, &bar_type, origin))
.map_err(|_| anyhow::anyhow!("year arithmetic underflow"))?; Prevention
- Bound Year step magnitudes at configuration validation.
- Keep input timestamps within ordinary years so the backward walk stays safe.
- Add fuzz tests for Year aggregation with extreme steps.
When it happens
Trigger: get_time_bar_start with a Year bar where year.checked_sub(step_i32) underflows i32 — requires a near-i32::MIN result, i.e. an extreme step_i32 and an extreme input year, or a negative step that passed earlier checks.
Common situations: Crafted/adversarial bar specs with near-i32::MAX magnitude steps; timestamps near the calendar era boundaries in synthetic data.
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
- `step` overflows i64 days
- `step` exceeds u32 range for month arithmetic
- `step` exceeds i32 range for year arithmetic
- year arithmetic overflow
- DurationNanos overflow in from_millis
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/fc3f44ce407cf4f2.
Report an issue: GitHub.