nautechsystems/nautilus_trader · error
Decimal overflow subtracting {rhs} from {lhs}
Error message
Decimal overflow subtracting {rhs} from {lhs} What it means
`checked_sub` wraps `Decimal::checked_sub` and raises this error when subtracting `rhs` from `lhs` would overflow the Decimal range (typically lhs very negative or rhs very large in magnitude). The error message includes both operands for diagnosis.
Source
Thrown at crates/model/src/data/bet.rs:771
}
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}"))
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use rust_decimal::Decimal;
use rust_decimal_macros::dec;View on GitHub (pinned to 18893faf8b)
Solutions
- Validate inputs upstream: ensure probabilities are within 0..1 and liabilities are within sane bounds before the subtraction.
- Log/inspect `lhs` and `rhs` from the error message to identify the bad operand.
- Sanitize feed data (clamp liabilities, reject NaN/absurd values) at ingestion time.
- If genuine large magnitudes are required, use a wider numeric representation for these calculations.
Example fix
// before let profit = checked_sub(proceeds, liability)?; // after assert!(liability.abs() < Decimal::from(1_000_000_000), "liability out of sane range"); let profit = checked_sub(proceeds, liability)?;
Defensive patterns
Strategy: validation
Validate before calling
fn valid_probability(p: Decimal) -> bool { p > Decimal::ZERO && p < Decimal::ONE }
fn sane_liability(v: Decimal) -> bool { v.abs() < Decimal::from(1_000_000_000) } Try / catch
let profit = profit_checked(&bet)
.map_err(|e| { log::error!("profit calc overflow: {e}"); e })?; Prevention
- Validate probabilities are strictly within 0..1 before inverse computations.
- Sanitize feed-provided liabilities with upper-bound clamps.
- Reject NaN-like or absurd values at market-data ingestion.
When it happens
Trigger: Callers `from_liability_checked`, `liability_checked`, `profit_checked`, or `inverse_probability_to_bet` subtracting liabilities/probability-derived values whose difference exceeds Decimal's representable range.
Common situations: Computing profit with an extreme liability value from a bad feed; an invalid probability (e.g. far outside 0..1) fed into `inverse_probability_to_bet` producing enormous reciprocals; negative liabilities of huge magnitude from corrupted 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
- Decimal overflow adding {lhs} and {rhs}
- 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/1dafbdf5d764ce21.
Report an issue: GitHub.