nautechsystems/nautilus_trader · error

Overflow in Money::from_mantissa_exponent

Error message

Overflow in Money::from_mantissa_exponent

What it means

Money::from_mantissa_exponent builds a Money from a mantissa and decimal exponent, converting the mantissa into a fixed-point raw via mantissa_exponent_to_fixed_i128 for the currency precision. When the intermediate i128 computation overflows (mantissa too large for the exponent/precision combination) the expect panics with this message.

Source

Thrown at crates/model/src/types/money.rs:281

    /// Creates a new [`Money`] 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 [`MONEY_RAW_MAX`] or [`MONEY_RAW_MIN`].
    #[must_use]
    pub fn from_mantissa_exponent(mantissa: i64, exponent: i8, currency: Currency) -> Self {
        check_fixed_precision(currency.precision).expect_display(FAILED);

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

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

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

        Self { raw, currency }
    }

    /// Creates a new [`Money`] instance with a value of zero with the given [`Currency`].
    ///

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Validate that mantissa magnitude is compatible with exponent and currency.precision before calling.
  2. Normalize the exponent first (shift digits so the mantissa is small) before constructing Money.
  3. Use the Money::new / from raw constructors with validated Decimal inputs instead.

Example fix

// before
let m = Money::from_mantissa_exponent(i64::MAX, -30, USD); // panics
// after
let dec = Decimal::new(mantissa, exponent.unsigned_abs()); // normalize via Decimal
let m = Money::new(dec, USD);
Defensive patterns

Strategy: validation

Validate before calling

let scaled = (mantissa as i128).checked_mul(10i128.pow(exponent.unsigned_abs() + currency.precision as u32));
if scaled.is_none() || scaled.unwrap().abs() > i128::MAX / 2 {
    return Err("mantissa/exponent out of representable range");
}
let m = Money::from_mantissa_exponent(mantissa, exponent, currency);

Type guard

fn mantissa_fits(mantissa: i64, exponent: i8, precision: u8) -> bool {
    (mantissa as i128)
        .checked_mul(10i128.pow((exponent.unsigned_abs() as u32).saturating_add(precision as u32)))
        .is_some()
}

Prevention

When it happens

Trigger: Money::from_mantissa_exponent(mantissa, exponent, currency) with a mantissa whose magnitude, when adjusted by exponent to the currency precision, exceeds i128 range — e.g. i64::MAX mantissa with a negative exponent demanding many extra digits.

Common situations: Constructing money amounts from raw exchange-feed mantissa/exponent pairs where the exponent assumption is wrong (off-by-N in exponent parsing), or accumulating huge totals before conversion.

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