nautechsystems/nautilus_trader · error

invalid probability: must be non-zero

Error message

invalid probability: must be non-zero

What it means

check_probability_non_zero rejects a probability of exactly zero because converting probability to odds requires dividing by it (odds = 1/probability), which is undefined for zero. The library exposes it as a public checked helper.

Source

Thrown at crates/model/src/data/bet.rs:694

/// Calculates the combined profit and loss for a slice of bets.
///
/// # Errors
///
/// Returns an error if a payoff or the running total overflows.
pub fn calc_bets_pnl_checked(bets: &[Bet]) -> anyhow::Result<Decimal> {
    bets.iter().try_fold(Decimal::ZERO, |acc, bet| {
        checked_add(acc, bet.outcome_win_payoff_checked()?)
    })
}

/// Checks that `probability` is non-zero.
///
/// # Errors
///
/// Returns an error if `probability` is zero.
pub fn check_probability_non_zero(probability: Decimal) -> anyhow::Result<()> {
    if probability.is_zero() {
        anyhow::bail!("invalid probability: must be non-zero")
    }
    Ok(())
}

/// Checks that `probability` is invertible (not equal to 1.0).
///
/// # Errors
///
/// Returns an error if `probability` is 1.0.
pub fn check_probability_invertible(probability: Decimal) -> anyhow::Result<()> {
    if probability == Decimal::ONE {
        anyhow::bail!("invalid probability: must not be 1.0 (inverse would be zero)")
    }
    Ok(())
}

/// Converts a probability and volume into a Bet.
///

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Validate probability > 0 (or > 1) before calling probability_to_bet
  2. Skip conversion for zero-probability outcomes at the caller level
  3. Fix upstream normalization so probabilities are never zero

Example fix

// before
let bet = probability_to_bet(Decimal::ZERO, side)?; // bails
// after
let p = Decimal::new(25, 2); // 0.25
anyhow::ensure!(!p.is_zero(), "skip zero-probability outcome");
let bet = probability_to_bet(p, side)?;
Defensive patterns

Strategy: validation

Validate before calling

if probability.is_zero() { return Ok(None); } // or skip the outcome
let bet = probability_to_bet(probability, side)?;

Type guard

fn is_usable_probability(p: Decimal) -> bool { !p.is_zero() }

Try / catch

match probability_to_bet(probability, side) {
    Err(e) if e.to_string().contains("must be non-zero") => { /* skip zero-probability outcome */ }
    other => other?,
}

Prevention

When it happens

Trigger: Calling check_probability_non_zero (directly or via probability_to_bet) with probability == Decimal::ZERO.

Common situations: Probabilities parsed from empty/placeholder data defaulting to 0; normalization bugs where all weights are zero leading to a zero probability; users mistaking zero for 'impossible event, skip' when they should skip the conversion themselves.

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


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