nautechsystems/nautilus_trader · error
Decimal overflow adding {lhs} and {rhs}
Error message
Decimal overflow adding {lhs} and {rhs} What it means
`checked_add` is the module's safe wrapper over `rust_decimal::Decimal::checked_add`. When adding two Decimal values overflows the fixed-precision Decimal range, the inner operation returns None and this error is raised with both operands in the message.
Source
Thrown at crates/model/src/data/bet.rs:766
}
fn check_odds_gt_one(price: Decimal) -> anyhow::Result<()> {
if price <= Decimal::ONE {
anyhow::bail!("Price must be greater than 1.0 for lay liability calculation, was {price}");
}
Ok(())
}
fn check_nonzero_denominator(value: Decimal, name: &str) -> anyhow::Result<()> {
if value.is_zero() {
anyhow::bail!("invalid {name}: must be non-zero")
}
Ok(())
}
fn checked_add(lhs: Decimal, rhs: Decimal) -> anyhow::Result<Decimal> {
lhs.checked_add(rhs)
.ok_or_else(|| anyhow::anyhow!("Decimal overflow adding {lhs} and {rhs}"))
}
fn checked_sub(lhs: Decimal, rhs: Decimal) -> anyhow::Result<Decimal> {
lhs.checked_sub(rhs)
.ok_or_else(|| anyhow::anyhow!("Decimal overflow subtracting {rhs} from {lhs}"))
}
fn checked_mul(lhs: Decimal, rhs: Decimal) -> anyhow::Result<Decimal> {
lhs.checked_mul(rhs)
.ok_or_else(|| anyhow::anyhow!("Decimal overflow multiplying {lhs} by {rhs}"))
}
fn checked_div(lhs: Decimal, rhs: Decimal) -> anyhow::Result<Decimal> {
check_nonzero_denominator(rhs, "divisor")?;
lhs.checked_div(rhs)
.ok_or_else(|| anyhow::anyhow!("Decimal overflow dividing {lhs} by {rhs}"))
}
View on GitHub (pinned to 18893faf8b)
Solutions
- Audit the operands in the failing call: log both values from the message and find which input is unexpectedly large.
- Cap or normalize exposure/PnL magnitudes before accumulation (e.g. convert to a smaller scale or use f64 for analytics).
- Fix the upstream value source (config, feed, or trade data) that produced the oversized operand.
- If legitimate huge sums are needed, switch those accumulations to a wider numeric type or arbitrary-precision decimal.
Defensive patterns
Strategy: validation
Validate before calling
fn within_decimal_range(v: Decimal) -> bool {
v.abs() < Decimal::from_i128_with_exp(7_900_000, 23) // ~7.9e28, Decimal max
} Try / catch
let pnl = calc_bets_pnl_checked(&bets)
.map_err(|e| { log::error!("PnL overflow: {e}"); e })?; Prevention
- Clamp or validate exposure/PnL magnitudes at ingestion boundaries.
- Keep currency units consistent (avoid mixing scaled units).
- Log accumulators periodically to spot runaway growth before overflow.
When it happens
Trigger: Any of the callers (`increased_state`, `decreased_state`, `realized_after_close`, `total_pnl_checked`, `calc_bets_pnl_checked`) summing exposures/PnL values whose magnitudes exceed Decimal's maximum (~7.9e28 with rust_decimal's default 96-bit representation).
Common situations: Accumulating PnL over very many bets without scaling; a runaway loop repeatedly adding a large exposure; unit/currency confusion producing values orders of magnitude too large; seeding a position with an already-huge value from a bad config.
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
- Decimal overflow subtracting {rhs} from {lhs}
- Decimal overflow multiplying {lhs} by {rhs}
- WETH balance overflow for included transaction {tx_hash} at
- invalid cumulative_quote_qty='{}' for cumulative_filled_qty=
- decimal `{value}` does not fit in i64
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/a647036f295bcd6f.
Report an issue: GitHub.