nautechsystems/nautilus_trader · error

Continuous-future adjustment exceeds PriceRaw range

Error message

Continuous-future adjustment exceeds PriceRaw range

What it means

After successfully scaling the adjustment to i128 fixed units, `set_adjustment` converts it to `PriceRaw` with `try_into().expect(...)`. On non-high-precision builds PriceRaw is i64, so an adjustment magnitude beyond i64 raw units panics.

Source

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

            return;
        }

        // Spread mode: scale the Decimal offset to FIXED_PRECISION once so the hot path
        // can add it straight onto `price.raw`. Signed PriceRaw supports negatives, so
        // backward-spread offsets that push prices below zero remain representable.
        self.adjustment_is_ratio = false;
        let exponent = -(adjustment.scale() as i8);
        let raw_i128 =
            mantissa_exponent_to_fixed_i128(adjustment.mantissa(), exponent, FIXED_PRECISION)
                .expect("Failed to scale continuous-future adjustment to fixed precision");

        #[allow(
            clippy::useless_conversion,
            reason = "i128 to PriceRaw is real when not high-precision"
        )]
        let raw: PriceRaw = raw_i128
            .try_into()
            .expect("Continuous-future adjustment exceeds PriceRaw range");

        self.adjustment_raw = raw;
        self.adjustment_active = self.adjustment_raw != 0;
    }

    fn apply_adjustment_to_price(&self, price: Price) -> Price {
        if !self.adjustment_active {
            return price;
        }

        if self.adjustment_is_ratio {
            // Multiply in double; `Price::new` rounds to the target precision.
            // Float can shift 1 ULP for high-precision raws (spread mode is exact).
            return Price::new(price.as_f64() * self.adjustment_ratio, price.precision);
        }

        // Spread: signed raw addition.
        Price::from_raw(price.raw + self.adjustment_raw, price.precision)

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Sanity-check/clamp the adjustment magnitude (e.g. reject |adj| beyond a plausible price bound) before calling `set_adjustment`
  2. Fix the upstream scaling so the mantissa is in real price units, not scaled by an extra power of ten
  3. Compile/use the high-precision build if legitimately large values are required
  4. Add a validation step at ingestion that drops or flags quotes with out-of-range adjustment factors

Example fix

// before
builder.set_adjustment(raw_index_price_scaled); // panics if beyond PriceRaw
// after
let adj_f = raw_index_price_scaled.as_f64();
assert!(adj_f.abs() < 1.0e9, "implausible adjustment: {adj_f}");
builder.set_adjustment(Price::new(adj_f, adjustment_price.precision()));
Defensive patterns

Strategy: validation

Validate before calling

// Rust: sanity-bound the adjustment before use
assert!(adj.as_f64().abs() < 1.0e9, "adjustment out of plausible range: {}", adj.as_f64());

Try / catch

let result = std::panic::catch_unwind(|| builder.set_adjustment(adj));

Prevention

When it happens

Trigger: Calling `set_adjustment` with an adjustment whose fixed-precision i128 value does not fit in PriceRaw (i64), e.g. an adjustment of billions of dollars expressed at 9-decimal fixed precision.

Common situations: Spread adjustments computed from mis-scaled feeds (mantissa multiplied by an extra 10^k); corrupted market data with absurd price levels; accidentally passing a cumulative index level instead of a per-step offset.

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