nautechsystems/nautilus_trader · error

Overflow occurred when adding `Money`

Error message

Overflow occurred when adding `Money`

What it means

The Add impl for Money adds the two raw fixed-point values with checked_add and panics with this message on overflow. Both operands must share currency precision; overflow means the sum exceeds the MoneyRaw representable range. The library treats arithmetic overflow as a bug-level panic rather than a silent wrap.

Source

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

}

impl Add for Money {
    type Output = Self;
    fn add(self, rhs: Self) -> Self::Output {
        assert_eq!(
            self.currency, rhs.currency,
            "Currency mismatch: cannot add {} to {}",
            rhs.currency.code, self.currency.code
        );
        assert!(
            raw_scales_match(self.currency.precision, rhs.currency.precision),
            "Cannot add `Money` values with mismatched decimal scales"
        );
        Self {
            raw: self
                .raw
                .checked_add(rhs.raw)
                .expect("Overflow occurred when adding `Money`"),
            currency: self.currency,
        }
    }
}

impl Sub for Money {
    type Output = Self;
    fn sub(self, rhs: Self) -> Self::Output {
        assert_eq!(
            self.currency, rhs.currency,
            "Currency mismatch: cannot subtract {} from {}",
            rhs.currency.code, self.currency.code
        );
        assert!(
            raw_scales_match(self.currency.precision, rhs.currency.precision),
            "Cannot subtract `Money` values with mismatched decimal scales"
        );
        Self {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check that the running total stays within MONEY range before each addition (compare against MONEY_RAW_MAX-scaled value).
  2. Aggregate in a wider type (i128/Decimal) and convert to Money only at the end.
  3. Compile with high-precision so MoneyRaw is i128, giving far more headroom.

Example fix

// before
let total = orders.iter().fold(Money::zero(USD), |acc, o| acc + o.notional()); // may panic
// after
let total_dec = orders.iter().fold(Decimal::ZERO, |acc, o| acc + o.notional().as_decimal());
let total = Money::new(total_dec, USD); // validate range once
Defensive patterns

Strategy: try-catch

Validate before calling

if a.raw.checked_add(b.raw).is_none() {
    return Err(overflow_err());
}
let sum = a + b;

Type guard

fn add_will_overflow(a: Money, b: Money) -> bool {
    a.raw.checked_add(b.raw).is_none()
}

Try / catch

// Money addition panics rather than returning Result; pre-check instead
if a.raw.checked_add(b.raw).is_none() {
    // handle overflow (cap, log, escalate)
} else {
    let sum = a + b;
}

Prevention

When it happens

Trigger: money_a + money_b where the raw sum exceeds MONEY_RAW_MAX, e.g. adding two near-maximum amounts of the same currency with matching precision.

Common situations: Accumulating PnL, balances, or notional totals over many trades until the running total exceeds the raw range; account aggregation jobs over large portfolios.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/26447e4e067b5edb. Report an issue: GitHub.