nautechsystems/nautilus_trader · error · anyhow::Error
Finalized Swap input
Error message
Finalized Swap input {base_amount} does not match the persisted amount {} What it means
For SELL orders, the finalized Swap event's base-side amount must be positive and equal in absolute value to the persisted plan.amount_in. A mismatch means the on-chain swap input differs from the amount the execution plan recorded, indicating the persisted record no longer describes the actual fill.
Solutions
- Confirm base/quote side selection (amount0 vs amount1) matches the pool's token ordering used when persisting amount_in
- Re-persist amount_in from the exact quote used at submission time (same decimals and scaling)
- Verify the tx really was the plan's transaction (check tx hash and router path); a different tx's log will not match
- If fees-on-transfer change effective input, compare against gross amount and account for the fee explicitly
Defensive patterns
Strategy: validation
Validate before calling
if order_side == OrderSide::Sell && !(base_amount.is_positive() && base_amount.unsigned_abs() == plan.amount_in) {
return Err(anyhow!("SELL input mismatch: event={} plan={}", base_amount, plan.amount_in));
} Try / catch
match verify_finalized_swap(...).await {
Err(e) if e.to_string().contains("does not match the persisted amount") => requote_and_replan(),
other => other,
} Prevention
- Persist amount_in from the exact executed quote with matching decimals
- Derive base/quote side from the pool's canonical token0/token1 ordering
- Assert tx hash and log index match the plan before amount comparison
- Re-verify plan amounts after any manual mutation or partial-fill logic
When it happens
Trigger: Verifying a SELL swap where event.amount0/amount1 (selected as base per token ordering) is <= 0, or its unsigned_abs() differs from plan.amount_in — e.g. the persisted plan amount was quoted pre-slippage/fee while the chain executed a different input, or amount0/amount1 were assigned to the wrong sides.
Common situations: Plan amount stored with different decimals scaling than the decoded event; token0/token1 ordering mismatch so base/quote amounts are swapped; the tx actually executed a partial or altered input after being front-run or partially filled; plan amount updated after submission without re-verifying.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Finalized Swap has no calculated trade information
- Finalized Swap input
- Finalized transaction
- Active terminal intent conflicts with the canonical nonce…
- Finalized Swap base amount
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/1bdfd3f1412ec4c4.
Report an issue: GitHub.
Appendix: source
Thrown at crates/adapters/blockchain/src/execution/client.rs:4777
let dex = crate::exchanges::get_dex_extended(plan.pool.chain.name, &plan.pool.dex.name)
.ok_or_else(|| {
anyhow::anyhow!(
"No RPC Swap decoder for {}:{}",
plan.pool.chain.name,
plan.pool.dex.name
)
})?;
let event = dex.parse_swap_event_rpc(log)?;
let (base_amount, quote_amount) =
if plan.pool.get_base_token().address == plan.pool.token0.address {
(event.amount0, event.amount1)
} else {
(event.amount1, event.amount0)
};
let last_qty = match plan.order.order_side() {
OrderSide::Sell => {
anyhow::ensure!(
base_amount.is_positive() && base_amount.unsigned_abs() == plan.amount_in,
"Finalized Swap input {base_amount} does not match the persisted amount {}",
plan.amount_in
);
plan.order.quantity()
}
OrderSide::Buy => {
anyhow::ensure!(
quote_amount.is_positive() && quote_amount.unsigned_abs() == plan.amount_in,
"Finalized Swap input {quote_amount} does not match the persisted amount {}",
plan.amount_in
);
anyhow::ensure!(
base_amount.is_negative(),
"Finalized Swap base amount {base_amount} is not a BUY output"
);
raw_amount_to_quantity(
base_amount.unsigned_abs(),View on GitHub (pinned to 18893faf8b)