nautechsystems/nautilus_trader · error

Fixed-point scale fits QuantityRaw

Error message

Fixed-point scale fits QuantityRaw

What it means

Quantity::mul multiplies two fixed-point quantities using checked_mul_div with a scale scalar. Before scaling, the code converts raw_scale(min precision) into a QuantityRaw (u64-backed); this panic fires when that scaled value cannot fit in QuantityRaw. It is an internal invariant: for precisions <= FIXED_PRECISION the scale should always fit, so hitting this indicates an unexpectedly large precision.

Source

Thrown at crates/model/src/types/quantity.rs:749

                .checked_sub(rhs.raw)
                .expect("Underflow occurred when subtracting `Quantity`"),
            precision: self.precision.max(rhs.precision),
        }
    }
}

impl Mul for Quantity {
    type Output = Self;
    fn mul(self, rhs: Self) -> Self::Output {
        let result_raw = if self.raw != QUANTITY_UNDEF
            && rhs.raw != QUANTITY_UNDEF
            && self.precision <= FIXED_PRECISION
            && rhs.precision <= FIXED_PRECISION
        {
            checked_mul_div_fixed(self.raw, rhs.raw)
        } else {
            let scalar = QuantityRaw::try_from(raw_scale(self.precision.min(rhs.precision)))
                .expect("Fixed-point scale fits QuantityRaw");
            checked_mul_div_raw(self.raw, rhs.raw, scalar)
        }
        .filter(|raw| *raw <= QUANTITY_RAW_MAX)
        .expect("Overflow occurred when multiplying `Quantity`");

        Self {
            raw: result_raw,
            precision: self.precision.max(rhs.precision),
        }
    }
}

impl Add<Decimal> for Quantity {
    type Output = Decimal;
    fn add(self, rhs: Decimal) -> Self::Output {
        self.as_decimal() + rhs
    }
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check the precision of both operands; cap them at FIXED_PRECISION before multiplying.
  2. Verify instrument definitions (price/size precision) are correct and within supported limits.
  3. If precision must exceed FIXED_PRECISION, use checked arithmetic or higher-width intermediates instead of relying on Quantity::mul.
  4. Report as a bug if it fires with precision <= FIXED_PRECISION; the invariant should hold.

Example fix

// before
let c = qty_a * qty_b; // panics if scaled raw overflows QuantityRaw
// after
assert!(qty_a.precision <= FIXED_PRECISION && qty_b.precision <= FIXED_PRECISION);
let c = qty_a * qty_b;
Defensive patterns

Strategy: validation

Validate before calling

fn can_mul(a: &Quantity, b: &Quantity) -> bool {
    a.precision <= FIXED_PRECISION
        && b.precision <= FIXED_PRECISION
        && a.raw.checked_mul(b.raw).map(|r| r <= QUANTITY_RAW_MAX).unwrap_or(false)
}

Type guard

fn precision_in_range(q: &Quantity) -> bool { q.precision <= FIXED_PRECISION }

Try / catch

// Rust panics are not catchable via Result; use catch_unwind if absolutely required
let result = std::panic::catch_unwind(|| a * b);

Prevention

When it happens

Trigger: Calling Quantity::mul (the `*` operator) on two Quantity values whose precision exceeds FIXED_PRECISION, so the else branch computes raw_scale(min(precision)) and the scaled divisor overflows QuantityRaw::try_from.

Common situations: Quantities constructed with very high precision (e.g. from exotic instrument definitions or misparsed instrument definitions with precision above the fixed-point limit), or a bug/overflow in raw_scale for the given precision.

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