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

  1. 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).
  2. Verify the pool was initialized (liquidity > 0) before quoting; an uninitialized pool yields a zero spot price.
  3. When constructing `SwapTradeInfo` manually, explicitly set `spot_price_before` from the pool's current price rather than leaving the default.
  4. 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

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


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