nautechsystems/nautilus_trader · error
days exceed signed duration range
Error message
days exceed signed duration range
What it means
After days × 24 succeeds, the hour count is converted to a SignedDuration via try_from_hours, which has its own narrower representable range. If hours fits i64 but exceeds the SignedDuration range, this error is thrown. Like the overflow sibling, it propagates through callers that may panic via unwrap.
Source
Thrown at crates/model/src/data/bar.rs:364
debug_assert_ne!(period_ns, 0, "bar period must be non-zero");
// Use div_euclid for floor division (rounds toward -inf, not zero)
// so negative deltas (now before origin) yield the previous period boundary
let num_periods = time_difference.as_nanos().div_euclid(period_ns);
base_time + SignedDuration::from_nanos_i128(num_periods * period_ns)
}
fn duration_days(days: i64) -> SignedDuration {
try_duration_days(days).unwrap_or_else(|e| panic!("{e}"))
}
fn try_duration_days(days: i64) -> anyhow::Result<SignedDuration> {
let hours = days
.checked_mul(24)
.ok_or_else(|| anyhow::anyhow!("days overflow i64 hours"))?;
SignedDuration::try_from_hours(hours)
.ok_or_else(|| anyhow::anyhow!("days exceed signed duration range"))
}
fn try_time_interval(step: usize, aggregation: BarAggregation) -> anyhow::Result<SignedDuration> {
let step_i64 = i64::try_from(step)
.map_err(|_| invalid_interval_step(step, aggregation, "step exceeds i64 range"))?;
let duration = match aggregation {
BarAggregation::Millisecond => SignedDuration::from_millis(step_i64),
BarAggregation::Second => SignedDuration::from_secs(step_i64),
BarAggregation::Minute => SignedDuration::try_from_mins(step_i64).ok_or_else(|| {
invalid_interval_step(step, aggregation, "step exceeds signed duration range")
})?,
BarAggregation::Hour => SignedDuration::try_from_hours(step_i64).ok_or_else(|| {
invalid_interval_step(step, aggregation, "step exceeds signed duration range")
})?,
BarAggregation::Day => try_scaled_days(step, aggregation, step_i64, 1)?,
BarAggregation::Week => try_scaled_days(step, aggregation, step_i64, 7)?,
BarAggregation::Month => try_scaled_days(step, aggregation, step_i64, 30)?,View on GitHub (pinned to 18893faf8b)
Solutions
- Clamp days to the SignedDuration-representable range before conversion
- Handle the error from try_duration_days instead of panicking via duration_days
- Validate configured bar intervals against known aggregation limits
Example fix
// before
let dur = duration_days(days);
// after
let dur = match try_duration_days(days) { Ok(d) => d, Err(e) => { warn!("{e}"); return Err(e); } }; Defensive patterns
Strategy: try-catch
Validate before calling
if days.abs() > (i64::MAX / 86_400_000_000) { bail!("days outside SignedDuration range"); } Try / catch
let dur = try_duration_days(days).unwrap_or_else(|e| { warn!("{e}"); fallback_duration }); Prevention
- Clamp day values to the SignedDuration range
- Prefer the Result-returning API over panicking wrappers
- Validate aggregation interval configuration at load time
When it happens
Trigger: Calling duration_days/try_scaled_days with days whose ×24 hour value is within i64 but outside SignedDuration::try_from_hours' accepted range (very large positive or negative day counts).
Common situations: Malformed or malicious interval configuration; tests probing duration limits; unbounded arithmetic on user-supplied aggregation steps.
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
- days overflow i64 hours
- {e}
- Invalid step in bar_type.spec.step: {step} for aggregation={
- WETH balance overflow for included transaction {tx_hash} at
- DurationNanos overflow in from_micros
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/2a3bdbd36ce09a19.
Report an issue: GitHub.