{"record":{"id":"5cf8bbfa96fbb54a","repo":"nautechsystems/nautilus_trader","slug":"e-5cf8bb","errorCode":null,"errorMessage":"{e}","messagePattern":"\\{e\\}","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/data/bet.rs","lineNumber":75,"sourceCode":"    }\n\n    /// Returns the bet's side.\n    #[must_use]\n    pub fn side(&self) -> BetSide {\n        self.side\n    }\n\n    /// Creates a bet from a stake or liability depending on the bet side.\n    ///\n    /// For `BetSide::Back` this calls [`Self::from_stake`] and for\n    /// `BetSide::Lay` it calls [`Self::from_liability`].\n    ///\n    /// # Panics\n    ///\n    /// Panics if `side` is [`BetSide::Lay`] and [`Self::from_liability`] panics.\n    #[must_use]\n    pub fn from_stake_or_liability(price: Decimal, volume: Decimal, side: BetSide) -> Self {\n        Self::from_stake_or_liability_checked(price, volume, side).unwrap_or_else(|e| panic!(\"{e}\"))\n    }\n\n    /// Creates a bet from a stake or liability depending on the bet side.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if `side` is [`BetSide::Lay`] and [`Self::from_liability_checked`] fails.\n    pub fn from_stake_or_liability_checked(\n        price: Decimal,\n        volume: Decimal,\n        side: BetSide,\n    ) -> anyhow::Result<Self> {\n        match side {\n            BetSide::Back => Ok(Self::from_stake(price, volume, side)),\n            BetSide::Lay => Self::from_liability_checked(price, volume, side),\n        }\n    }\n","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/2114cf6f761429e0adb5ca9596fcd7b895b16011/crates/model/src/data/bet.rs#L57-L93","documentation":"`Bet::from_stake_or_liability` builds a Back bet directly from a stake, but for a Lay bet it derives the stake from a liability via `from_liability_checked`. The panicking wrapper surfaces that checked failure when `price` (decimal odds) is not greater than 1.0 ('Price must be greater than 1.0 for lay liability calculation, was {price}') or when `liability / (price - 1)` overflows. The Back branch can never panic.","triggerScenarios":"Calling `from_stake_or_liability(price, volume, BetSide::Lay)` with price <= 1.0 — price exactly 1.0 (the divisor price-1 would be zero) or a probability like 0.35 passed where decimal odds are expected — or with liability magnitudes that overflow Decimal in the division.","commonSituations":"Betting/prediction-market adapters converting exchange messages: probability (0..1) fed instead of decimal odds, feed prices of exactly 1.0 for near-certain outcomes, placeholder values in unit tests, or mis-scaled volumes (raw token base units).","solutions":["Pass decimal odds strictly greater than 1.0 as price on the Lay path, converting probabilities with 1/p first.","Switch to `from_stake_or_liability_checked` and handle the Result instead of the panicking wrapper.","Reject or quarantine market data with price <= 1.0 before constructing bets.","If the message mentions Decimal overflow, check for corrupted or mis-scaled volume fields."],"exampleFix":"// before: probability used directly as odds on the lay path\nlet bet = Bet::from_stake_or_liability(prob, volume, BetSide::Lay); // panics: price must be > 1.0\n\n// after: convert probability to decimal odds, use the checked API\nlet odds = Decimal::ONE.checked_div(prob).context('zero probability')?;\nlet bet = Bet::from_stake_or_liability_checked(odds, volume, BetSide::Lay)?;","handlingStrategy":"validation","validationCode":"fn can_build_from_volume(price: Decimal, side: BetSide) -> bool {\n    match side {\n        BetSide::Back => true,\n        BetSide::Lay => price > Decimal::ONE,\n    }\n}","typeGuard":null,"tryCatchPattern":"let bet = Bet::from_stake_or_liability_checked(odds, volume, side)\n    .with_context(|| format('cannot build {side} bet at {odds} from volume {volume}'))?;","preventionTips":["Convert probabilities to decimal odds (1/p) at ingest.","Reject lay-side prices <= 1.0 before bet construction.","Unit-test boundary prices exactly 1.0 and 0.99."],"tags":["rust","nautilustrader","betting","panic","odds","validation"],"backgroundTag":"invalid-argument-panic","analyzedSha":"2114cf6f761429e0adb5ca9596fcd7b895b16011","analyzedAt":"2026-08-21T11:28:30.864Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}