{"record":{"id":"2d39e159339455d6","repo":"nautechsystems/nautilus_trader","slug":"price-must-be-greater-than-1-0-for-lay-liability-c","errorCode":null,"errorMessage":"Price must be greater than 1.0 for lay liability calculation, was {price}","messagePattern":"Price must be greater than 1\\.0 for lay liability calculation, was (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/data/bet.rs","lineNumber":752,"sourceCode":"///\n/// The side is also inverted (BUY becomes SELL and vice versa).\n///\n/// # Errors\n///\n/// Returns an error if `probability` is 1.0 or its inverse is zero.\npub fn inverse_probability_to_bet(\n    probability: Decimal,\n    volume: Decimal,\n    side: OrderSide,\n) -> anyhow::Result<Bet> {\n    check_probability_invertible(probability)?;\n    let inverse_probability = checked_sub(Decimal::ONE, probability)?;\n    probability_to_bet(inverse_probability, volume, side.opposite())\n}\n\nfn check_odds_gt_one(price: Decimal) -> anyhow::Result<()> {\n    if price <= Decimal::ONE {\n        anyhow::bail!(\"Price must be greater than 1.0 for lay liability calculation, was {price}\");\n    }\n    Ok(())\n}\n\nfn check_nonzero_denominator(value: Decimal, name: &str) -> anyhow::Result<()> {\n    if value.is_zero() {\n        anyhow::bail!(\"invalid {name}: must be non-zero\")\n    }\n    Ok(())\n}\n\nfn checked_add(lhs: Decimal, rhs: Decimal) -> anyhow::Result<Decimal> {\n    lhs.checked_add(rhs)\n        .ok_or_else(|| anyhow::anyhow!(\"Decimal overflow adding {lhs} and {rhs}\"))\n}\n\nfn checked_sub(lhs: Decimal, rhs: Decimal) -> anyhow::Result<Decimal> {\n    lhs.checked_sub(rhs)","sourceCodeStart":734,"sourceCodeEnd":770,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/data/bet.rs#L734-L770","documentation":"check_odds_gt_one rejects odds of 1.0 or below when constructing a bet from a lay liability. Lay liability is computed via 1/odds arithmetic, which is only meaningful (and non-negative/finite) for odds strictly greater than 1.0. The guard bails with the offending price embedded in the message.","triggerScenarios":"Calling Bet::from_liability_checked (or its internal check_odds_gt_one) with price <= Decimal::ONE, e.g. odds of exactly 1.0, 0.0, or a negative value.","commonSituations":"Feeds delivering pre-race odds of 1.0 as a placeholder; unit errors where probability (0-1) is passed where decimal odds (>=1) are expected; uninitialized/zero price fields.","solutions":["Pass decimal odds strictly greater than 1.0; validate the value before constructing the bet.","Check whether a probability is being passed where decimal odds are required and convert (odds = 1/probability) first.","Reject or skip records with odds <= 1.0 at ingestion instead of passing them into from_liability_checked."],"exampleFix":"// before\nlet bet = Bet::from_liability_checked(Decimal::ZERO, liability)?; // odds <= 1.0\n// after\nanyhow::ensure!(odds > Decimal::ONE, \"lay odds must be > 1.0, got {odds}\");\nlet bet = Bet::from_liability_checked(odds, liability)?;","handlingStrategy":"validation","validationCode":"// Rust\nuse rust_decimal::Decimal;\nfn valid_lay_odds(p: Decimal) -> bool { p > Decimal::ONE }\n// Python\n# assert price > 1.0, f\"lay odds must be > 1.0, got {price}\"","typeGuard":null,"tryCatchPattern":"// Rust\nmatch Bet::from_liability_checked(price, liability) {\n    Ok(b) => b,\n    Err(e) if e.to_string().starts_with(\"Price must be greater than 1.0\") => skip_record(price),\n    Err(e) => return Err(e),\n}","preventionTips":["Distinguish probabilities (0..1) from decimal odds (>1) with distinct types or field names.","Sanity-check feed data ranges at ingestion and drop placeholder odds of 1.0.","Reject non-positive prices before any liability math."],"tags":["decimal","validation","betting","odds"],"backgroundTag":"value-out-of-range","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}