{"record":{"id":"fd65b646f274795e","repo":"nautechsystems/nautilus_trader","slug":"overflow-in-price-from-mantissa-exponent","errorCode":null,"errorMessage":"Overflow in Price::from_mantissa_exponent","messagePattern":"Overflow in Price::from_mantissa_exponent","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/model/src/types/price.rs","lineNumber":525,"sourceCode":"\n    /// Creates a new [`Price`] from a mantissa/exponent pair using pure integer arithmetic.\n    ///\n    /// The value is `mantissa * 10^exponent`. This avoids all floating-point and Decimal\n    /// operations, making it ideal for exchange data that arrives as mantissa/exponent pairs.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the resulting raw value exceeds [`PRICE_RAW_MAX`] or [`PRICE_RAW_MIN`].\n    #[must_use]\n    pub fn from_mantissa_exponent(mantissa: i64, exponent: i8, precision: u8) -> Self {\n        check_fixed_precision(precision).expect_display(FAILED);\n\n        if mantissa == 0 {\n            return Self { raw: 0, precision };\n        }\n\n        let raw_i128 = mantissa_exponent_to_fixed_i128(i128::from(mantissa), exponent, precision)\n            .expect(\"Overflow in Price::from_mantissa_exponent\");\n\n        #[allow(\n            clippy::useless_conversion,\n            reason = \"i128 to PriceRaw is real when not high-precision\"\n        )]\n        let raw: PriceRaw = raw_i128\n            .try_into()\n            .expect(\"Raw value exceeds PriceRaw range in Price::from_mantissa_exponent\");\n        assert!(\n            raw >= PRICE_RAW_MIN && raw <= PRICE_RAW_MAX,\n            \"`raw` value {raw} exceeded bounds [{PRICE_RAW_MIN}, {PRICE_RAW_MAX}] for Price\"\n        );\n\n        Self { raw, precision }\n    }\n\n    /// Checked variant of [`Price::from_mantissa_exponent`].\n    ///","sourceCodeStart":507,"sourceCodeEnd":543,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/types/price.rs#L507-L543","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Reduce the mantissa magnitude or use an exponent consistent with the instrument's precision so the scaled value fits in i128.","Pre-check the magnitude: compute the intended decimal value and confirm |value| * 10^precision < 2^127 before calling.","Clamp or reject the input price at the data-ingestion boundary (validate against instrument price precision and max price).","If you need larger ranges, perform the computation in a big-integer/Decimal type first and only construct Price once it fits."],"exampleFix":"// before\nlet price = Price::from_mantissa_exponent(9999999999_i64, 30, 9); // panics: scaled value overflows i128\n// after\nlet price = Price::from_mantissa_exponent(1234567_i64, -4, 9); // 123.4567 at precision 9, fits i128","handlingStrategy":"validation","validationCode":"// Rust\nfn can_build_price(mantissa: i64, exponent: i8, precision: u8) -> bool {\n    // |mantissa| * 10^(exponent - precision) must fit i128\n    let diff = i32::from(exponent) - i32::from(precision);\n    const I128_MAX_LOG10: i32 = 38;\n    mantissa.abs() <= i64::MAX / 2\n        && (mantissa.checked_ilog10().map(|d| d as i32).unwrap_or(0) + diff) <= I128_MAX_LOG10\n}","typeGuard":"fn fits_i128(value: Decimal, precision: u8) -> bool {\n    let scaled = value * Decimal::from(10_u32.pow(u32::from(precision)));\n    scaled.abs() <= Decimal::from(i128::MAX)\n}","tryCatchPattern":null,"preventionTips":["Validate instrument tick-size/precision config at load time and reject absurd exponents.","Convert external price strings through Decimal and range-check before constructing Price.","Keep exponents aligned with the instrument's declared precision.","Add unit tests for boundary prices at max precision."],"tags":["rust","arithmetic-overflow","panic","price"],"backgroundTag":"value-out-of-range","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}