nautechsystems/nautilus_trader · error
Slippage {slippage_bps} bps must be below {BPS_DENOMINATOR}
Error message
Slippage {slippage_bps} bps must be below {BPS_DENOMINATOR} What it means
derive_min_amount_out reduces the quoted output by slippage_bps basis points to compute the minimum accepted output. BPS_DENOMINATOR is 10_000 (100%), so a slippage of 10_000 bps or more would drive the minimum to zero or negative, removing slippage protection entirely; such values are rejected before any math runs.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:2490
fn exact_output_amount(quote: &SwapQuote, zero_for_one: bool) -> anyhow::Result<U256> {
let amount = if zero_for_one {
quote.amount1
} else {
quote.amount0
};
if !amount.is_negative() {
anyhow::bail!("Swap quote output amount {amount} is not a positive output");
}
Ok(amount.unsigned_abs())
}
/// Derives the minimum output accepted for the swap: the quoted output reduced by
/// `slippage_bps`, in exact integer arithmetic. Rejects a zero minimum, which would leave
/// the swap without slippage protection.
fn derive_min_amount_out(quoted_amount_out: U256, slippage_bps: u32) -> anyhow::Result<U256> {
if slippage_bps >= BPS_DENOMINATOR {
anyhow::bail!("Slippage {slippage_bps} bps must be below {BPS_DENOMINATOR}");
}
let min_amount_out = quoted_amount_out
.checked_mul(U256::from(BPS_DENOMINATOR - slippage_bps))
.and_then(|scaled| scaled.checked_div(U256::from(BPS_DENOMINATOR)))
.ok_or_else(|| anyhow::anyhow!("Minimum output derivation overflow"))?;
if min_amount_out.is_zero() {
anyhow::bail!(
"Derived minimum output is zero for quoted output {quoted_amount_out} at {slippage_bps} bps slippage"
);
}
Ok(min_amount_out)
}
#[async_trait(?Send)]
impl ExecutionClient for BlockchainExecutionClient {
fn is_connected(&self) -> bool {
self.core.is_connected()
}View on GitHub (pinned to 2114cf6f76)
Solutions
- Pass slippage in basis points strictly below 10_000: 0.5% = 50, 1% = 100, 5% = 500
- Convert percent configs at the boundary: slippage_bps = (percent * 100) as u32, and assert it is < 10_000
- Sanity-check the value in tests/config validation so the mistake surfaces at startup, not mid-swap
Example fix
// before: percent used as bps / 100% tolerance let slippage_bps = 50; // user meant 50 percent -> 5000 is still fine, but 10000 is not let slippage_bps = 10000; // Err: must be below 10000 // after: convert percent -> bps and keep it under 100% let percent = 0.5; let slippage_bps = (percent * 100.0) as u32; assert!(slippage_bps < 10_000);
Defensive patterns
Strategy: validation
Validate before calling
const BPS_DENOMINATOR: u32 = 10_000;
anyhow::ensure!(slippage_bps < BPS_DENOMINATOR, "slippage {slippage_bps} bps must be < {BPS_DENOMINATOR}"); Type guard
fn valid_slippage_bps(bps: u32) -> bool { bps < 10_000 } Try / catch
// Pure input error: correct the value at the call site; retrying with the same bps // always fails. Fail fast at config load instead of catching here.
Prevention
- Convert percent to bps in exactly one place: bps = (percent * 100) as u32
- Validate slippage config at startup with a hard assert (< 10_000)
- Document the unit (basis points) next to every slippage field
When it happens
Trigger: Passing slippage_bps >= 10_000 to the swap execution path: a value of 10_000 meant as '100% tolerance', a percentage accidentally used as bps (e.g. 50 for 50%), or a fraction scaled wrongly (0.5 passed instead of 50).
Common situations: Config files that express slippage in percent while the API expects bps; strategies copying slippage from a different venue's units; defensive 'very high' slippage values like 100000 used in volatile markets.
Related errors
- `slippage_bps` {slippage_bps} exceeds `max_slippage_bps` {ma
- Order quantity must be positive
- slippage_bps parameter {value} exceeds the u32 range
- height must be positive, was {self.height}
- pandas is required for report generation; install it with `p
AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21).
Data as JSON: /api/errors/3c7047c5860f0de3.
Report an issue: GitHub.