nautechsystems/nautilus_trader · critical

Overflow in Price::from_mantissa_exponent

Error message

Overflow in Price::from_mantissa_exponent

What it means

Price::from_mantissa_exponent builds a fixed-point Price by converting a mantissa+exponent into a fixed i128 raw value via mantissa_exponent_to_fixed_i128; when the scaled value cannot be represented in i128 at the requested precision, that helper returns None and this expect panics. The library throws it because Price stores a bounded fixed-point raw integer and silently wrapping would corrupt prices.

Source

Thrown at crates/model/src/types/price.rs:525

    /// Creates a new [`Price`] from a mantissa/exponent pair using pure integer arithmetic.
    ///
    /// The value is `mantissa * 10^exponent`. This avoids all floating-point and Decimal
    /// operations, making it ideal for exchange data that arrives as mantissa/exponent pairs.
    ///
    /// # Panics
    ///
    /// Panics if the resulting raw value exceeds [`PRICE_RAW_MAX`] or [`PRICE_RAW_MIN`].
    #[must_use]
    pub fn from_mantissa_exponent(mantissa: i64, exponent: i8, precision: u8) -> Self {
        check_fixed_precision(precision).expect_display(FAILED);

        if mantissa == 0 {
            return Self { raw: 0, precision };
        }

        let raw_i128 = mantissa_exponent_to_fixed_i128(i128::from(mantissa), exponent, precision)
            .expect("Overflow in Price::from_mantissa_exponent");

        #[allow(
            clippy::useless_conversion,
            reason = "i128 to PriceRaw is real when not high-precision"
        )]
        let raw: PriceRaw = raw_i128
            .try_into()
            .expect("Raw value exceeds PriceRaw range in Price::from_mantissa_exponent");
        assert!(
            raw >= PRICE_RAW_MIN && raw <= PRICE_RAW_MAX,
            "`raw` value {raw} exceeded bounds [{PRICE_RAW_MIN}, {PRICE_RAW_MAX}] for Price"
        );

        Self { raw, precision }
    }

    /// Checked variant of [`Price::from_mantissa_exponent`].
    ///

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Reduce the mantissa magnitude or use an exponent consistent with the instrument's precision so the scaled value fits in i128.
  2. Pre-check the magnitude: compute the intended decimal value and confirm |value| * 10^precision < 2^127 before calling.
  3. Clamp or reject the input price at the data-ingestion boundary (validate against instrument price precision and max price).
  4. If you need larger ranges, perform the computation in a big-integer/Decimal type first and only construct Price once it fits.

Example fix

// before
let price = Price::from_mantissa_exponent(9999999999_i64, 30, 9); // panics: scaled value overflows i128
// after
let price = Price::from_mantissa_exponent(1234567_i64, -4, 9); // 123.4567 at precision 9, fits i128
Defensive patterns

Strategy: validation

Validate before calling

// Rust
fn can_build_price(mantissa: i64, exponent: i8, precision: u8) -> bool {
    // |mantissa| * 10^(exponent - precision) must fit i128
    let diff = i32::from(exponent) - i32::from(precision);
    const I128_MAX_LOG10: i32 = 38;
    mantissa.abs() <= i64::MAX / 2
        && (mantissa.checked_ilog10().map(|d| d as i32).unwrap_or(0) + diff) <= I128_MAX_LOG10
}

Type guard

fn fits_i128(value: Decimal, precision: u8) -> bool {
    let scaled = value * Decimal::from(10_u32.pow(u32::from(precision)));
    scaled.abs() <= Decimal::from(i128::MAX)
}

Prevention

When it happens

Trigger: Calling Price::from_mantissa_exponent(mantissa, exponent, precision) where mantissa scaled by 10^(exponent - precision) or 10^(precision - exponent) exceeds i128 range, e.g. a very large mantissa combined with a large positive exponent, or a huge precision gap requiring a massive 10^n multiplier.

Common situations: Parsing exchange instrument definitions with absurd tick-size exponents; ingesting bad venue config where precision is set far larger than the mantissa supports; hand-constructing prices from strings with wrong exponent conventions.

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