nautechsystems/nautilus_trader · error

Finalized Swap side {} does not match {} order

Error message

Finalized Swap side {} does not match {} order

What it means

After a finalized swap's trade info is computed, the adapter asserts that the trade's `order_side` matches the side of the originating order in the execution plan. This `ensure!` failure means the on-chain swap executed in the opposite or different direction than the client order requested (e.g. a BUY order produced a SELL-side swap). It guards against executing fills that contradict the user's intent.

Source

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

        included.block_number,
        included.receipt.block_hash
    );
    let timestamp_ns = block
        .timestamp
        .checked_mul(NANOSECONDS_IN_SECOND)
        .ok_or_else(|| anyhow::anyhow!("Finalized block timestamp overflows nanoseconds"))?;
    let mut swap = event.to_pool_swap(
        plan.pool.chain.clone(),
        plan.instrument_id,
        plan.pool.pool_identifier,
        UnixNanos::from(timestamp_ns),
    );
    swap.calculate_trade_info(&plan.pool.token0, &plan.pool.token1, None)?;
    let trade = swap
        .trade_info
        .as_ref()
        .ok_or_else(|| anyhow::anyhow!("Finalized Swap has no calculated trade information"))?;
    anyhow::ensure!(
        trade.order_side == plan.order.order_side(),
        "Finalized Swap side {} does not match {} order",
        trade.order_side,
        plan.order.order_side()
    );
    let gas_cost = included
        .receipt
        .effective_gas_price
        .checked_mul(U256::from(included.receipt.gas_used))
        .ok_or_else(|| anyhow::anyhow!("Finalized transaction gas commission overflow"))?;
    let commission = Money::from_u256(gas_cost, plan.pool.chain.native_currency())?;
    let trade_digest = keccak256(format!("{}:{}", included.tx_hash, swap.log_index));
    let trade_digest = trade_digest.to_string();
    let trade_id = TradeId::new_checked(&trade_digest[2..38])?;

    if plan
        .order
        .trade_ids()

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check the pool's token0/token1 ordering in the deployment manifest matches what the order side expects
  2. Confirm the order side (Buy/Sell) in the plan is correct for the pool's quote/base direction
  3. Re-derive the swap path so the swap direction aligns with the order side before execution
  4. If using a router, verify it did not flip the swap direction (e.g. exact-input vs exact-output path)

Example fix

// before: order side assumed to match pool direction
let swap = build_swap(plan, included)?;
// after: assert direction before submitting
let expected_side = if swap.token_in == plan.pool.token0 { OrderSide::Buy } else { OrderSide::Sell };
anyhow::ensure!(expected_side == plan.order.order_side(), "plan side misconfigured for pool direction");
Defensive patterns

Strategy: validation

Validate before calling

// before submitting the plan, confirm side matches pool direction
let swap_side = if swap.token_in == plan.pool.token0 { OrderSide::Buy } else { OrderSide::Sell };
assert_eq!(swap_side, plan.order.order_side(), "order side inconsistent with pool direction");

Try / catch

if let Err(e) = execute_plan(&plan).await {
    if e.to_string().contains("does not match") {
        log::error!("order/pool side mismatch: review token0/token1 ordering in manifest");
    }
}

Prevention

When it happens

Trigger: A finalized swap's `TradeInfo.order_side` differs from `plan.order.order_side()` — typically when the swap direction through token0/token1 is misinterpreted (quote/base inversion), the order was placed on the wrong side for the pool, or a router routed the swap in the reverse direction.

Common situations: Inverted token ordering in pool configuration (token0/token1 swapped relative to the manifest); placing a BUY order against a pool whose price direction the adapter interprets oppositely; copying an order/plan between chains or pools with different token ordering conventions.

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/6ca6c512daeb1c81. Report an issue: GitHub.