nautechsystems/nautilus_trader · error

year arithmetic overflow

Error message

year arithmetic overflow

What it means

In the forward year walk, checked_add(step_i32) computes the next candidate year; if the addition overflows i32 the expect panics. With a sane positive step the break condition fires long before i32 overflow, so this signals an extreme step value or pathological input year.

Source

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

                        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.aggregation
        ),
    }
}

/// Finds the closest smaller time based on a daily time origin and period.
///

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Set a realistic Year step (small positive integer) in the bar spec.
  2. Validate 0 < step and now_year + step <= i32::MAX (practically <= ~9000 for jiff) before constructing the BarType.
  3. Reject invalid bar specs at configuration load rather than at runtime.
  4. Report a bug if overflow occurs with a plausible step.

Example fix

// before
let bar_type = BarType::from_spec(2_000_000_000, BarAggregation::Year);
// after
let step = 2_000_000_000.min(9_000); // clamp or reject absurd steps
assert!(step > 0);
let bar_type = BarType::from_spec(step, BarAggregation::Year);
Defensive patterns

Strategy: validation

Validate before calling

let step = step_to_i64(spec.step);
let now_year = i64::from(Offset::UTC.to_datetime(now).year());
if step <= 0 || now_year + step > 9_000 {
    return Err(format!("year step {step} would overflow the year walk"));
}

Type guard

fn year_walk_safe(now_year: i32, step: i64) -> bool {
    step > 0 && now_year as i64 + 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 overflow"))?;

Prevention

When it happens

Trigger: get_time_bar_start with a Year bar where repeatedly adding step_i32 to `year` exceeds i32::MAX before year_start(next_year) > now — requires a step near i32::MAX (near the earlier i32 conversion limit) plus an in-range `now`.

Common situations: Misconfigured Year bar specs with billion-year steps from unit confusion; programmatic spec generation without validation; range-probing tests.

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/19ac712e2d9417d9. Report an issue: GitHub.