nautechsystems/nautilus_trader · error · anyhow::Error

Finalized Swap log position does not match transaction {}

Error message

Finalized Swap log position does not match transaction {}

What it means

This ensure! validates that the finalized Swap log's transaction hash, block number, transaction index, and block hash all match the verified inclusion receipt. When the position (tx hash / block number / tx index / block hash combination) disagrees, the log does not belong to the transaction the library tracked — a reorg, mismatched response, or parsing error.

Source

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

                && log.topics.first().is_some_and(|topic| topic == &signature)
                && Address::from_str(&log.address).ok() == Some(plan.pool_address)
        })
        .collect::<Vec<_>>();
    anyhow::ensure!(
        swap_logs.len() == 1,
        "Finalized transaction {} emitted {} Swap logs from expected pool {}; expected exactly one",
        included.tx_hash,
        swap_logs.len(),
        plan.pool_address
    );
    let log = swap_logs[0];
    let log_transaction_hash = B256::from_str(&rpc_log::extract_transaction_hash(log)?)
        .with_context(|| "Invalid finalized Swap log transaction hash")?;
    let log_block_hash = log
        .block_hash
        .as_deref()
        .ok_or_else(|| anyhow::anyhow!("Finalized Swap log has no block hash"))?;
    anyhow::ensure!(
        log_transaction_hash == included.tx_hash
            && rpc_log::extract_block_number(log)? == included.block_number
            && u64::from(rpc_log::extract_transaction_index(log)?)
                == included.receipt.transaction_index
            && B256::from_str(log_block_hash)
                .with_context(|| "Invalid finalized Swap log block hash")?
                == included.receipt.block_hash,
        "Finalized Swap log position does not match transaction {}",
        included.tx_hash
    );

    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
            )

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Re-query logs/receipt after confirming chain finality; a reorg invalidates the previous inclusion data
  2. Verify you query the same chain/network the plan's pool belongs to
  3. Check that extract_block_number/extract_transaction_index parse hex-vs-decimal consistently with the provider
  4. Restart verification from the receipt fetch so all fields come from one consistent response
Defensive patterns

Strategy: validation

Validate before calling

if log_tx_hash != included.tx_hash || log_block_number != included.block_number || log_tx_index as u64 != included.receipt.transaction_index { return Err(anyhow!("log position mismatch")); }

Try / catch

match verify_log_position(&log, &included) {
    Err(e) if is_reorg_indicator(&e) => wait_for_finality_and_retry(tx_hash).await,
    Err(e) => return Err(e),
    Ok(()) => {},
}

Prevention

When it happens

Trigger: The RPC returned a Swap log whose transactionHash, blockNumber, transactionIndex or blockHash differs from included.tx_hash / included.block_number / included.receipt.transaction_index / included.receipt.block_hash — e.g. logs fetched for the wrong block range after a reorg.

Common situations: Chain reorganization moved the tx to another block; provider returned logs from a cached/stale block; mixing hex and decimal block numbers so the comparison fails; duplicate tx hashes across chains when querying the wrong network.

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


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