nautechsystems/nautilus_trader · error
Decimal overflow dividing {lhs} by {rhs}
Error message
Decimal overflow dividing {lhs} by {rhs} What it means
`checked_div` first verifies the denominator is non-zero (via `check_nonzero_denominator`), then wraps `Decimal::checked_div`, raising this error if the division itself overflows the Decimal range (e.g. dividing by an extremely small non-zero denominator).
Source
Thrown at crates/model/src/data/bet.rs:782
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}"))
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use rust_decimal::Decimal;
use rust_decimal_macros::dec;
use super::*;
fn dec_str(s: &str) -> Decimal {
s.parse::<Decimal>().expect("Failed to parse Decimal")
}
#[rstest]
#[should_panic(expected = "Liability-based betting is only applicable for Lay side.")]
fn test_from_liability_panics_on_back_side() {
let _ = Bet::from_liability(dec!(2.0), dec!(100.0), BetSide::Back);View on GitHub (pinned to 18893faf8b)
Solutions
- Validate the denominator against a minimum sane threshold (not just non-zero) before dividing.
- Inspect the operands in the message to find which value is a near-zero denominator or oversized numerator.
- Sanitize probabilities/odds at ingestion (clamp to e.g. [1e-6, 1.0]) so reciprocals stay in range.
- If a genuine extreme quotient is expected, use a wider numeric type for that calculation.
Example fix
// before
let stake = checked_div(liability, probability)?;
// after
let min_prob = Decimal::new(1, 6); // 0.000001
if probability < min_prob { return Err(anyhow!("probability {probability} too small")); }
let stake = checked_div(liability, probability)?; Defensive patterns
Strategy: validation
Validate before calling
let min_denom = Decimal::new(1, 6); // 0.000001
if denominator.abs() < min_denom {
return Err(anyhow!("denominator {denominator} too close to zero"));
} Try / catch
let stake = hedging_stake_checked(&bet)
.map_err(|e| { log::error!("hedge calc overflow: {e}"); e })?; Prevention
- Enforce a minimum-threshold check on denominators, not just non-zero.
- Clamp probabilities/odds to e.g. [1e-6, 1.0] at ingestion.
- Sanitize market data before any reciprocal or ratio computation.
When it happens
Trigger: Callers such as `from_liability_checked`, `hedging_stake_checked`, `as_bet_checked`, `increased_state`, `decreased_state`, or `flattening_bet_checked` dividing by a near-zero denominator (e.g. a probability of ~1e-28) so the quotient overflows.
Common situations: Converting liability to back/stake amounts with a near-zero probability from a bad odds feed; a zero-ish scale factor slipping past the non-zero check; extreme hedging ratios computed from corrupt market data.
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
- invalid cumulative_quote_qty='{}' for cumulative_filled_qty=
- decimal `{value}` does not fit in i64
- commission calculation overflow
- Decimal overflow adding {lhs} and {rhs}
- Decimal overflow subtracting {rhs} from {lhs}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/4d4add3cae3d1dd9.
Report an issue: GitHub.