{"record":{"id":"54c8fea1a287bb6c","repo":"nautechsystems/nautilus_trader","slug":"cannot-calculate-metric-the-spot-price-before-i","errorCode":null,"errorMessage":"Cannot calculate {metric}, the spot price before is zero","messagePattern":"Cannot calculate (.+?), the spot price before is zero","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/defi/data/swap_trade_info.rs","lineNumber":134,"sourceCode":"    pub fn get_slippage_bps(&self) -> anyhow::Result<u32> {\n        if let Some(spot_price_before) = self.spot_price_before {\n            Self::check_spot_price_before(spot_price_before, PriceMetric::Slippage)?;\n            let price_change = self.execution_price - spot_price_before;\n            let slippage =\n                (price_change.as_decimal() / spot_price_before.as_decimal()).abs() * dec!(10_000);\n\n            Ok(slippage.round().to_u32().unwrap_or(0))\n        } else {\n            anyhow::bail!(\"Cannot calculate slippage, the spot price before is not set\")\n        }\n    }\n\n    fn check_spot_price_before(\n        spot_price_before: Price,\n        metric: PriceMetric,\n    ) -> anyhow::Result<()> {\n        let metric = metric.name();\n        anyhow::ensure!(\n            !spot_price_before.is_zero(),\n            \"Cannot calculate {metric}, the spot price before is zero\"\n        );\n        Ok(())\n    }\n}\n\nenum PriceMetric {\n    Impact,\n    Slippage,\n}\n\nimpl PriceMetric {\n    const fn name(self) -> &'static str {\n        match self {\n            Self::Impact => \"price impact\",\n            Self::Slippage => \"slippage\",\n        }","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/defi/data/swap_trade_info.rs#L116-L152","documentation":"SwapTradeInfo metric calculations (e.g. slippage bps) need the spot price captured before the swap to compute price impact. `check_spot_price_before` is a guard that fails fast with `anyhow::ensure!` when the recorded pre-trade spot price is `Price::zero()`, because division by or comparison against zero would produce meaningless or panicking results. It signals that the caller never populated the pre-swap spot price on the quote.","triggerScenarios":"Calling methods like `calculate_trade_info` / `get_slippage_bps` on a `SwapTradeInfo` whose `spot_price_before` field was left as zero — e.g. computing a quote without capturing the pool state prior to the swap, or constructing trade info manually without setting spot_price_before.","commonSituations":"Backtesting or replay code that snapshots pool state only after executing a swap; simulation harnesses that build `SwapTradeInfo` by hand and forget the pre-trade price; pools newly created where the observed spot price defaulted to zero.","solutions":["Capture the pool spot price before executing the swap and store it in the quote/trade info (e.g. via `swap_exact_in` with the pre-trade price parameter set).","Verify the pool was initialized (liquidity > 0) before quoting; an uninitialized pool yields a zero spot price.","When constructing `SwapTradeInfo` manually, explicitly set `spot_price_before` from the pool's current price rather than leaving the default.","If zero genuinely means 'unavailable', treat it upstream and skip the metric instead of calling the calculation."],"exampleFix":"// before\nlet quote = profiler.swap_exact_in(size, zero_for_one, None)?;\nquote.calculate_trade_info(&profiler.pool.token0, &profiler.pool.token1)?;\n// after\nlet spot_before = profiler.pool.price();  // capture BEFORE the swap\nlet quote = profiler.swap_exact_in(size, zero_for_one, Some(spot_before))?;\nquote.calculate_trade_info(&profiler.pool.token0, &profiler.pool.token1)?;","handlingStrategy":"validation","validationCode":"if quote.trade_info.as_ref().map_or(true, |t| t.spot_price_before.is_zero()) {\n    anyhow::bail!(\"spot price before swap is zero; capture pool price pre-swap\");\n}","typeGuard":"fn has_spot_price(info: &SwapTradeInfo) -> bool { !info.spot_price_before.is_zero() }","tryCatchPattern":"let slippage = quote.trade_info.as_ref().and_then(|t| t.get_slippage_bps().ok()).unwrap_or_else(|| {\n    eprintln!(\"slippage unavailable: spot price before swap is zero\");\n    f64::NAN\n});","preventionTips":["Always snapshot pool price before applying a swap to a profiler","Assert non-zero price right after pool initialization/loading","Use the library's quote API which records spot_price_before automatically instead of hand-building SwapTradeInfo"],"tags":["defi","arithmetic","uninitialized-value"],"backgroundTag":"invalid-argument-value","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"}