nautechsystems/nautilus_trader · error

`step` exceeds i64 range

Error message

`step` exceeds i64 range

What it means

`step_to_i64` converts the bar aggregation step from `NonZeroUsize` to `i64` because subsequent time arithmetic operates on i64 nanosecond values. It panics if the step value is larger than i64::MAX. On 64-bit platforms this only occurs with absurdly large step values, so the panic signals a nonsensical bar specification.

Source

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

    let days = step_i64
        .checked_mul(multiplier)
        .ok_or_else(|| invalid_interval_step(step, aggregation, "step overflows i64 days"))?;
    try_duration_days(days).map_err(|e| invalid_interval_step(step, aggregation, &e.to_string()))
}

fn invalid_interval_step(step: usize, aggregation: BarAggregation, reason: &str) -> anyhow::Error {
    anyhow::anyhow!(
        "Invalid step in bar_type.spec.step: {step} for aggregation={aggregation}. {reason}"
    )
}

/// Converts a bar specification step to `i64` for time arithmetic.
///
/// # Panics
///
/// Panics if `step` exceeds the `i64` range.
fn step_to_i64(step: NonZeroUsize) -> i64 {
    i64::try_from(step.get()).expect("`step` exceeds i64 range")
}

/// Represents a bar aggregation specification including a step, aggregation
/// method/rule and price type.
#[repr(C)]
#[derive(
    Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Serialize, Deserialize, Builder,
)]
#[builder(build_fn(validate = "Self::validate"))]
#[serde(try_from = "BarSpecificationFields")]
#[cfg_attr(
    feature = "python",
    pyo3::pyclass(module = "nautilus_trader.model", from_py_object)
)]
#[cfg_attr(
    feature = "python",
    pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.model")
)]

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Validate the bar step is a realistic value (< i64::MAX, practically much smaller) before constructing the BarType
  2. Check where the step value originates — config files, CLI args, or API input — and clamp it
  3. Use the domain types (e.g. u32-based steps where available) so oversized values fail at construction time

Example fix

// before
let bar_type = BarType::new(instrument_id, step_from_config, agg, price_type);
// after
assert!(step_from_config <= i64::MAX as usize, "bar step too large");
let bar_type = BarType::new(instrument_id, step_from_config, agg, price_type);
Defensive patterns

Strategy: validation

Validate before calling

def validate_bar_step(step: int) -> int:
    if not (0 < step < 2**63):
        raise ValueError(f"bar step {step} exceeds i64 range")
    return step

Try / catch

try:
    interval = bar_type.get_interval()
except Exception as e:
    logger.error(f"invalid bar spec step: {e}")
    raise ValueError("bar step must be a realistic positive integer") from e

Prevention

When it happens

Trigger: Constructing a `BarType`/`BarAggregation` specification with a step (e.g. minute, second, tick count) exceeding 9,223,372,036,854,775,807 and then calling `get_bar_interval`, `get_time_bar_start`, or `timedelta` on it.

Common situations: Programmatically generated bar specs where a config value or multiplier is wrong (e.g. seconds supplied in nanoseconds); user input passed unvalidated into bar aggregation step; malicious or corrupted spec deserialization.

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/2306a25f73424c60. Report an issue: GitHub.