nautechsystems/nautilus_trader · error

`step` overflows raw quantity units for volume aggregation

Error message

`step` overflows raw quantity units for volume aggregation

What it means

`step_as_quantity_raw` converts a `BarAggregation` step (usize) into raw quantity units by multiplying FIXED_SCALAR by the step with `checked_mul`. If the product overflows QuantityRaw the `.expect` panics, because silently truncating an aggregation step would produce wrong bars.

Source

Thrown at crates/data/src/aggregation.rs:1903

}

fn is_below_min_size_decimal(size: Decimal, precision: u8) -> bool {
    quantity_from_decimal(size, precision).raw == 0
}

fn min_size_decimal(precision: u8) -> Decimal {
    Decimal::new(1, u32::from(precision))
}

fn quantity_from_decimal(size: Decimal, precision: u8) -> Quantity {
    Quantity::from_decimal_dp(size, precision).expect(FAILED)
}

// Converts a bar specification step to raw quantity units with exact integer arithmetic
fn step_as_quantity_raw(step: usize) -> QuantityRaw {
    (FIXED_SCALAR as QuantityRaw)
        .checked_mul(step as QuantityRaw)
        .expect("`step` overflows raw quantity units for volume aggregation")
}

/// Provider for vega per leg (option spreads). Returns `None` when greeks are unavailable.
pub trait VegaProvider {
    /// Returns vega for the given leg instrument, or `None` if not available.
    fn vega_for_leg(&self, instrument_id: InstrumentId) -> Option<f64>;
}

/// Rounder for spread bid/ask (e.g. tick scheme). When absent, raw prices are used with instrument precision.
pub trait SpreadPriceRounder {
    /// Rounds raw bid/ask to valid prices (handles negative prices with mirroring when using tick scheme).
    fn round_prices(&self, raw_bid: f64, raw_ask: f64, precision: u8) -> (Price, Price);
}

/// Vega provider that returns leg vegas from a map (e.g. populated from greeks cache).
#[derive(Debug, Default)]
pub struct MapVegaProvider {
    vegas: AHashMap<InstrumentId, f64>,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Reduce the aggregation step to a realistic quantity value (step * 1e9 must fit in i64, so keep step below ~9.2e9)
  2. Validate the step upper bound when parsing bar specifications and reject early with a clear message
  3. Check config for double-scaling: don't pass already-raw quantity units as the step

Example fix

// before
let spec = BarAggregationSpec::new(InstrumentId::from("..."), BarAggregation::Volume, step: usize::MAX, ...);
// after
assert!(step <= 9_000_000_000, "volume aggregation step too large: {step}");
let spec = BarAggregationSpec::new(id, BarAggregation::Volume, step, ...);
Defensive patterns

Strategy: validation

Validate before calling

// Rust: bound the step so FIXED_SCALAR * step fits QuantityRaw
const MAX_STEP: usize = (i64::MAX as usize) / 1_000_000_000;
assert!(step >= 1 && step <= MAX_STEP, "invalid volume aggregation step: {step}");

Try / catch

let result = std::panic::catch_unwind(|| step_as_quantity_raw(step));

Prevention

When it happens

Trigger: Configuring volume aggregation with an enormous step value (e.g. `BarAggregationSpec` step near usize::MAX or >= QuantityRaw::MAX / FIXED_SCALAR, i.e. above ~1.8e10 at i64 raw and 1e9 scalar).

Common situations: Typo or unit confusion in bar spec strings (step given in satoshis/wei-like raw units then multiplied again); automated config generation producing giant steps; passing a duration or nanosecond value where a quantity step is expected.

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