nautechsystems/nautilus_trader · error
`step` exceeds u32 range for month arithmetic
Error message
`step` exceeds u32 range for month arithmetic
What it means
For Month bars, the aggregation step (an i64) is converted to u32 because add_n_months/subtract_n_months take u32 month counts. If the bar spec's step is negative or exceeds u32::MAX, try_from fails and the expect panics. The function documents this: `step` must be representable for the calendar arithmetic.
Source
Thrown at crates/model/src/data/bar.rs:274
BarAggregation::Month => {
// Set to the first day of the year
let now_civil = Offset::UTC.to_datetime(now);
let mut start_time = Offset::UTC
.to_timestamp(
Date::new(now_civil.year(), 1, 1)
.expect("valid year start date")
.at(0, 0, 0, 0),
)
.expect("valid UTC year start");
start_time += origin_offset;
if now < start_time {
start_time =
subtract_n_months(start_time, 12).expect("Failed to subtract 12 months");
}
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::UTCView on GitHub (pinned to 18893faf8b)
Solutions
- Correct the bar spec step to the intended number of months (a small positive integer).
- Validate step <= u32::MAX before constructing/registering the Month bar type.
- Guard the call: check spec.aggregation and spec.step bounds before calling get_time_bar_start.
- Use a Year aggregation instead if the intended period is many months.
Example fix
// before BarType::from_spec(step: 5_000_000_000, BarAggregation::Month) // after assert!(step > 0 && step <= u32::MAX as i64); BarType::from_spec(step, BarAggregation::Month)
Defensive patterns
Strategy: validation
Validate before calling
fn validate_month_step(spec: &BarSpec) -> Result<(), String> {
if spec.aggregation != BarAggregation::Month { return Ok(()); }
let step = step_to_i64(spec.step);
if step <= 0 { return Err("month step must be positive".into()); }
if step > u32::MAX as i64 { return Err("month step exceeds u32 range".into()); }
Ok(())
} Type guard
fn valid_month_step(step: i64) -> bool { step > 0 && step <= u32::MAX as i64 } Try / catch
let start = std::panic::catch_unwind(|| get_time_bar_start(now, &bar_type, origin))
.map_err(|_| anyhow::anyhow!("invalid month step for {bar_type}"))?; Prevention
- Validate BarType steps at configuration parse time, not at timer registration.
- Watch for unit confusion (nanoseconds vs months) when building specs programmatically.
- Add round-trip tests for every bar spec loaded from config.
When it happens
Trigger: Registering or computing a time bar with BarAggregation::Month and a step value > 4,294,967,295 months (e.g. step_to_i64 of a huge spec step) or a negative step reaching this branch.
Common situations: Typo or unit mistake in a bar spec (e.g. passing nanoseconds as the month step); programmatically generated BarType specs with unchecked step values; adversarial or corrupted configuration where the step field holds a raw byte value.
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 i32 range for year arithmetic
- year arithmetic underflow
- year arithmetic overflow
- DurationNanos overflow in from_millis
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/60fb0307922ef59d.
Report an issue: GitHub.