nautechsystems/nautilus_trader · error · anyhow::Error

slippage_bps parameter {value} exceeds the u32 range

Error message

slippage_bps parameter {value} exceeds the u32 range

What it means

The SubmitOrder command's params carried a 'slippage_bps' key read as u64, and its value did not fit in u32 (max 4,294,967,295). The per-order override is converted with u32::try_from before being compared against max_slippage_bps, so oversized values are rejected before quoting. In practice the value is a unit mistake rather than a deliberate 42-million-bps slippage request.

Source

Thrown at crates/adapters/blockchain/src/execution/client.rs:1218

                quote_token.address
            );
        }

        let amount_in = quantity_to_raw_amount(order.quantity(), base_token.decimals)?;
        if amount_in > U256::from(self.transaction_limits.max_order_amount) {
            anyhow::bail!(
                "Order amount {amount_in} exceeds the configured `max_order_amount` {}",
                self.transaction_limits.max_order_amount
            );
        }

        let slippage_bps = match cmd
            .params
            .as_ref()
            .and_then(|params| params.get_u64("slippage_bps"))
        {
            Some(value) => u32::try_from(value).map_err(|_| {
                anyhow::anyhow!("slippage_bps parameter {value} exceeds the u32 range")
            })?,
            None => self.transaction_limits.slippage_bps,
        };

        if slippage_bps > self.transaction_limits.max_slippage_bps {
            anyhow::bail!(
                "Slippage {slippage_bps} bps exceeds the configured `max_slippage_bps` {}",
                self.transaction_limits.max_slippage_bps
            );
        }

        let profiler = self
            .core
            .cache()
            .pool_profiler(&instrument_id)
            .cloned()
            .ok_or_else(|| {
                anyhow::anyhow!(

View on GitHub (pinned to 2114cf6f76)

Solutions

  1. Send slippage in basis points as a small integer: 50 = 0.50%, 200 = 2%
  2. Ensure the value fits u32 and is at or below the configured transaction_limits.max_slippage_bps (which itself must be < 10000)
  3. If you did not intend an override, omit 'slippage_bps' entirely and let the default slippage_bps limit apply

Example fix

# before
order = self.order_factory.market(
    instrument_id,
    order_side=OrderSide.SELL,
    quantity=base_qty,
    params={'slippage_bps': 5_000_000_000},  # exceeds u32
)

# after: 0.50% slippage in basis points
order = self.order_factory.market(
    instrument_id,
    order_side=OrderSide.SELL,
    quantity=base_qty,
    params={'slippage_bps': 50},
)
Defensive patterns

Strategy: validation

Validate before calling

def sanitized_slippage_bps(params: dict | None, max_allowed: int) -> int | None:
    """Return a safe per-order slippage override, or None to use the default."""
    if not params or 'slippage_bps' not in params:
        return None
    value = params['slippage_bps']
    assert isinstance(value, int) and 0 <= value <= 0xFFFFFFFF, 'slippage_bps must fit u32'
    assert value <= max_allowed, f'slippage_bps above max_slippage_bps={max_allowed}'
    return value

Type guard

def valid_slippage_param(params: dict | None) -> bool:
    v = (params or {}).get('slippage_bps')
    return v is None or (isinstance(v, int) and not isinstance(v, bool) and 0 <= v <= 0xFFFFFFFF)

Prevention

When it happens

Trigger: submit_order with params like {'slippage_bps': 50_000_000_000} — e.g. slippage passed in wei-style raw units, in hundredths of a bip, or a percentage multiplied by the wrong scale.

Common situations: Strategy code computing slippage from a Decimal price and forgetting to cast through a bounded integer; passing 1/1e9-style fractions scaled into a u64; config templates using different bps conventions between teams.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21). Data as JSON: /api/errors/e1b4f5b56f1ed232. Report an issue: GitHub.