nautechsystems/nautilus_trader · error · anyhow::Error

Price limit must be greater than current price for one_for_z

Error message

Price limit must be greater than current price for one_for_zero swaps

What it means

For one_for_zero swaps (token1 -> token0) the pool price must move UP, so the supplied sqrt price limit must be strictly greater than the current sqrt price. validate_price_limit bails if limit_price_sqrt <= current price_sqrt_ratio_x96, because the swap could never reach such a limit going in that direction.

Source

Thrown at crates/model/src/defi/pool_analysis/profiler.rs:883

    /// Validates that the price limit is in the correct direction for the swap.
    ///
    /// # Errors
    /// Returns error if price limit violates swap direction constraints.
    fn validate_price_limit(
        &self,
        limit_price_sqrt: U160,
        zero_for_one: bool,
    ) -> anyhow::Result<()> {
        if zero_for_one {
            // Swapping token0 for token1: price must decrease
            if limit_price_sqrt >= self.state.price_sqrt_ratio_x96 {
                anyhow::bail!("Price limit must be less than current price for zero_for_one swaps");
            }
        } else {
            // Swapping token1 for token0: price must increase
            if limit_price_sqrt <= self.state.price_sqrt_ratio_x96 {
                anyhow::bail!(
                    "Price limit must be greater than current price for one_for_zero swaps"
                );
            }
        }

        Ok(())
    }

    /// Processes a mint (liquidity add) event from historical data.
    ///
    /// Updates pool state when liquidity is added to a position, validates ticks,
    /// and delegates to internal liquidity management methods.
    ///
    /// # Errors
    ///
    /// This function returns an error if:
    /// - Pool is not initialized.
    /// - Tick range is invalid or not properly spaced.

View on GitHub (pinned to 18893faf8b)

Solutions

  1. For one_for_zero swaps pass the maximum sqrt price sentinel (e.g. MAX_SQRT_RATIO) unless a tighter bound is intended
  2. Validate limit > state.price_sqrt_ratio_x96 before calling, or recompute from the current price
  3. Verify the zero_for_one flag matches the intended swap direction
  4. Use None as the limit when any price movement is acceptable

Example fix

// before
let quote = profiler.quote_swap(amount, false, Some(current_sqrt_price))?;
// after
let limit = MAX_SQRT_PRICE_X96; // must exceed current price for one_for_zero
let quote = profiler.quote_swap(amount, false, Some(limit))?;
Defensive patterns

Strategy: validation

Validate before calling

if !zero_for_one {
    anyhow::ensure!(limit > profiler.current_sqrt_price(), "limit must be above current price");
}

Type guard

fn valid_one_for_zero_limit(limit: U160, current: U160) -> bool { limit > current }

Try / catch

match profiler.quote_swap(amount, false, Some(limit)) {
    Ok(q) => q,
    Err(e) if e.to_string().contains("must be greater than current price") => {
        profiler.quote_swap(amount, false, Some(MAX_SQRT_PRICE_X96))?
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling quote_swap with sqrt_price_limit_x96 = Some(limit) where zero_for_one is false and limit <= current sqrt price — typically using the MIN sentinel instead of MAX, or a stale limit computed at an earlier price.

Common situations: Copying example code with the wrong sentinel constant; limits cached from a previous block before the price moved; inverted direction flags; passing current price as the limit.

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/17703c24bd60b033. Report an issue: GitHub.