nautechsystems/nautilus_trader · error
Cannot calculate {metric}, the spot price before is zero
Error message
Cannot calculate {metric}, the spot price before is zero What it means
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.
Source
Thrown at crates/model/src/defi/data/swap_trade_info.rs:134
pub fn get_slippage_bps(&self) -> anyhow::Result<u32> {
if let Some(spot_price_before) = self.spot_price_before {
Self::check_spot_price_before(spot_price_before, PriceMetric::Slippage)?;
let price_change = self.execution_price - spot_price_before;
let slippage =
(price_change.as_decimal() / spot_price_before.as_decimal()).abs() * dec!(10_000);
Ok(slippage.round().to_u32().unwrap_or(0))
} else {
anyhow::bail!("Cannot calculate slippage, the spot price before is not set")
}
}
fn check_spot_price_before(
spot_price_before: Price,
metric: PriceMetric,
) -> anyhow::Result<()> {
let metric = metric.name();
anyhow::ensure!(
!spot_price_before.is_zero(),
"Cannot calculate {metric}, the spot price before is zero"
);
Ok(())
}
}
enum PriceMetric {
Impact,
Slippage,
}
impl PriceMetric {
const fn name(self) -> &'static str {
match self {
Self::Impact => "price impact",
Self::Slippage => "slippage",
}View on GitHub (pinned to 18893faf8b)
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.
Example fix
// before let quote = profiler.swap_exact_in(size, zero_for_one, None)?; quote.calculate_trade_info(&profiler.pool.token0, &profiler.pool.token1)?; // after let spot_before = profiler.pool.price(); // capture BEFORE the swap let quote = profiler.swap_exact_in(size, zero_for_one, Some(spot_before))?; quote.calculate_trade_info(&profiler.pool.token0, &profiler.pool.token1)?;
Defensive patterns
Strategy: validation
Validate before calling
if quote.trade_info.as_ref().map_or(true, |t| t.spot_price_before.is_zero()) {
anyhow::bail!("spot price before swap is zero; capture pool price pre-swap");
} Type guard
fn has_spot_price(info: &SwapTradeInfo) -> bool { !info.spot_price_before.is_zero() } Try / catch
let slippage = quote.trade_info.as_ref().and_then(|t| t.get_slippage_bps().ok()).unwrap_or_else(|| {
eprintln!("slippage unavailable: spot price before swap is zero");
f64::NAN
}); Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Trade info not initialized
- Router allowance {allowance} is below the swap amount {} for
- Input token {} balance {balance} is below the swap amount {}
- WETH balance overflow for included transaction {tx_hash} at
- Native currency not specified for chain {}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/54c8fea1a287bb6c.
Report an issue: GitHub.