nautechsystems/nautilus_trader · error

Local quote for {instrument_id} produced a zero quote input

Error message

Local quote for {instrument_id} produced a zero quote input

What it means

For SELL orders the local quote must fill the full base_amount; the code compares the quote's filled amount (I256) with the order's base_amount and bails when they differ. Note the source excerpt shows this check fires with a distinct "zero quote input" message at line 1684 when the quote input computed for the local quote is zero — meaning the simulated swap had nothing to fill against, typically because the computed input amount was zero.

Source

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

        }
        let profiler_position = profiler.last_processed_event.clone().ok_or_else(|| {
            anyhow::anyhow!("Pool profiler for {instrument_id} has processed no events")
        })?;

        let zero_for_one = token_in == pool.token0.address;
        let (amount_in, quoted_amount_out) = match order.order_side() {
            OrderSide::Sell => {
                let quote = profiler
                    .swap_exact_in(base_amount, zero_for_one, None)
                    .map_err(|e| anyhow::anyhow!("Swap quote failed for {instrument_id}: {e}"))?;
                let amount_filled = if zero_for_one {
                    quote.amount0
                } else {
                    quote.amount1
                };

                if amount_filled != I256::from(base_amount) {
                    anyhow::bail!(
                        "Local quote for {instrument_id} filled {amount_filled} of the {base_amount} order amount; pool liquidity cannot fill the order"
                    );
                }
                (base_amount, exact_output_amount(&quote, zero_for_one)?)
            }
            OrderSide::Buy => {
                let quote = profiler
                    .swap_exact_out(base_amount, zero_for_one, None)
                    .map_err(|e| anyhow::anyhow!("Swap quote failed for {instrument_id}: {e}"))?;
                let amount_in = quote.get_input_amount();
                if amount_in.is_zero() {
                    anyhow::bail!("Local quote for {instrument_id} produced a zero quote input");
                }
                let ceiling = quote_spend_ceiling.ok_or_else(|| {
                    anyhow::anyhow!(
                        "No `quote_spend_limits` entry for BUY token pair {token_in} -> {token_out}"
                    )
                })?;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Increase the order quantity so the raw amount is non-zero and representable at base token decimals.
  2. Check the pool's liquidity — use a more liquid pool or split the order.
  3. Verify the pool profiler state is fresh (re-sync) so the local quote simulates against current liquidity.

Example fix

// before
let qty = 0.0000001; // rounds to 0 raw units
client.submit_order(cmd, &order)?;
// after
let raw = quantity_to_raw_amount(qty, base_token.decimals)?;
assert!(raw > U256::zero(), "order quantity rounds to zero");
client.submit_order(cmd, &order)?;
Defensive patterns

Strategy: validation

Validate before calling

// Rust
let raw = quantity_to_raw_amount(order.quantity(), base_token.decimals)?;
if raw.is_zero() {
    return Err(anyhow::anyhow!("order quantity rounds to zero raw units"));
}

Prevention

When it happens

Trigger: submit_order (SELL path) where the local quote simulation computes a zero input amount, or where amount_filled != base_amount because pool liquidity cannot fill the order size.

Common situations: Very small order sizes that round to zero raw units; an illiquid or empty pool that cannot fill the order; stale profiler state producing a degenerate quote.

Related errors


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