nautechsystems/nautilus_trader · error

Transaction {} reverted on-chain

Error message

Transaction {} reverted on-chain

What it means

After waiting for inclusion, the transaction receipt shows status Reverted: the transaction was mined but its execution failed on-chain (e.g. the swap reverted). The client records a terminal Reverted status in the database, emits the event, releases the in-flight slot, and bails so the caller sees the failure.

Source

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

            InclusionOutcome::Reverted(mut included) => {
                included.finality.decisions.extend(
                    verify_finalized_transaction(
                        &included,
                        &intent,
                        prepared.nonce,
                        &prepared.raw_tx,
                        self,
                        purpose.as_str(),
                    )
                    .await?,
                );
                self.commit_verified_finality(&included, TransactionStatus::Reverted, &[])
                    .await?;
                self.database
                    .mark_execution_event_emitted(prepared.intent_id, "terminal")
                    .await?;
                self.release_slot();
                anyhow::bail!("Transaction {} reverted on-chain", included.tx_hash)
            }
            InclusionOutcome::Pending(message) => anyhow::bail!(message),
        }
    }

    /// Claims the single in-flight slot before any preparation RPC call, so the `pending`
    /// nonce read stays authoritative: a second transaction is rejected before it can sign.
    fn claim_slot(&self, purpose: TransactionPurpose) -> anyhow::Result<()> {
        let mut slot = self.in_flight.lock();
        if let Some(in_flight) = *slot {
            return Err(in_flight_limit_error(&in_flight));
        }
        *slot = Some(InFlightSlot::Preparing(purpose));
        Ok(())
    }

    /// Runs the read-only pre-signing pipeline: chain ID verification, nonce selection, fee
    /// and gas policy checks, transaction building, and local signing.

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the revert reason from the receipt/trace to identify the on-chain failure
  2. Widen slippage_bps or re-quote before resubmitting
  3. Re-check balances, allowances, and pool state at current block before retry
  4. Simulate the transaction pre-sign to catch reverts before spending gas

Example fix

// before
let quote = client.quote(pool, amount).await?;
client.submit_order(order_with(quote)).await?;
// after
let quote = client.quote(pool, amount).await?;
client.prepare_and_simulate(quote, slippage_bps).await?; // pre-sign simulation
client.submit_order(order_with(quote)).await?;
Defensive patterns

Strategy: validation

Validate before calling

// Pre-sign simulation catches most reverts before gas is spent
let sim = client.simulate_transaction(&tx).await?;
anyhow::ensure!(sim.succeeded(), "tx would revert: {:?}", sim.reason);

Try / catch

match res {
    Err(e) if e.to_string().contains("reverted on-chain") => {
        let reason = client.fetch_revert_reason(tx_hash).await?;
        // adjust slippage/state and resubmit
    }
    r => r?,
}

Prevention

When it happens

Trigger: A submitted transaction (e.g. a swap or approval) was included in a block but executed with a revert — the EVM rolled back its effects while gas was still consumed.

Common situations: Slippage tolerance too tight so minAmountOut not met at execution time; token transfer/approval failing on-chain; pool price moved between quote and inclusion; insufficient balance at execution block.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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