nautechsystems/nautilus_trader · error
quantity for {currency} exceeds Money raw bounds
Error message
quantity for {currency} exceeds Money raw bounds What it means
wallet_money_from_quantity converts a Quantity's raw integer value into a Money amount in the account currency. After adjusting the raw value for the currency's precision it performs a fixed-width i128 range check (check_fixed_raw_i128) and then attempts to fit the value into Money's internal raw integer representation (MoneyRaw). If the value is too large to fit that narrower integer type, the TryInto conversion fails and this error is thrown.
Source
Thrown at crates/portfolio/src/manager.rs:1443
let scale = 10_i128.pow(u32::from(target_precision - source_precision));
raw.checked_mul(scale).ok_or_else(|| {
anyhow::anyhow!("quantity for {currency} overflowed while increasing raw scale")
})?
}
Ordering::Greater => {
let scale = 10_i128.pow(u32::from(source_precision - target_precision));
anyhow::ensure!(
raw % scale == 0,
"quantity for {currency} loses precision when decreasing raw scale"
);
raw / scale
}
Ordering::Equal => raw,
};
check_fixed_raw_i128(raw, currency.precision)?;
let raw: MoneyRaw = raw
.try_into()
.map_err(|_| anyhow::anyhow!("quantity for {currency} exceeds Money raw bounds"))?;
Money::from_raw_checked(raw, currency).map_err(Into::into)
}
fn reservation_precisions_match(
account: &dyn Account,
reservations: &AHashMap<Currency, Money>,
) -> bool {
for reservation in reservations.values() {
let Some(balance) = account.balance(Some(reservation.currency)) else {
continue;
};
if balance.currency.precision != reservation.currency.precision {
log::error!(
"Cannot update {} reservation: precision {} differed from balance precision {}",
reservation.currency,
reservation.currency.precision,View on GitHub (pinned to 18893faf8b)
Solutions
- Verify the quantity/balance value from the venue is scaled correctly for the currency precision before it reaches the wallet
- Check currency.precision: low-precision currencies (fewer decimals) allow less headroom before overflow — use a higher-precision currency or cap the value
- Confirm the build's MoneyRaw width (fixed i128 bounds via check_fixed_raw_i128) matches the magnitudes your strategy trades
- Log the failing quantity, currency, and precision at the call site to confirm which side (quantity vs precision scaling) produces the out-of-range value
Example fix
// before: passing a raw quantity already scaled for the venue, re-scaled again let money = wallet_money_from_quantity(&qty, &usd_currency)?; // after: ensure the quantity is in units, not scaled raw, before conversion let qty = Quantity::new(balance_total.as_f64(), usd_currency.precision); let money = wallet_money_from_quantity(&qty, &usd_currency)?;
Defensive patterns
Strategy: validation
Validate before calling
fn quantity_fits_money_raw(qty: &Quantity, currency: &Currency) -> bool {
let raw = qty.raw.as_i128();
// 10^precision scaling must stay within i128 bounds used by MoneyRaw
let scaled = raw.checked_mul(10i128.checked_pow(currency.precision as u32).unwrap_or(i128::MAX));
match scaled {
Some(v) => v >= i128::MIN / 1_000_000 && v <= i128::MAX / 1_000_000, // conservative bound
None => false,
}
} Prevention
- Validate venue-reported balances against a sane maximum before applying them to the wallet
- Prefer currencies/precisions that give headroom for your position sizes
- Scale quantities correctly once at the adapter boundary, not repeatedly downstream
When it happens
Trigger: Calling update_balance_locked_wallet (directly or via balance updates) with a quantity whose raw value, after precision adjustment to the currency's precision, exceeds the maximum (or minimum) value representable by MoneyRaw — e.g. very large account balances in low-precision currencies like USD (2 dp).
Common situations: Trading venues or test environments reporting enormous balances; manually seeded account state with unadjusted raw quantities; currencies with few decimals where a large quantity multiplied by precision overflows; bugs in upstream balance parsing that pass unscaled values.
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
- Failed to convert Quantity raw value: {e}
- Quantity overflow for ticks={ticks}, decimals={decimals}: {e
- invalid quantity `{value}` at precision {precision}: {e}
- notional calculation overflow
- total PnL overflow
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/c99888b086bd0600.
Report an issue: GitHub.