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
- Read the revert reason from the receipt/trace to identify the on-chain failure
- Widen slippage_bps or re-quote before resubmitting
- Re-check balances, allowances, and pool state at current block before retry
- 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
- Always simulate before signing to catch reverts early
- Re-quote immediately before submission and use sane slippage_bps
- Verify balances and allowances at the latest block
- Monitor receipt revert reasons to tune parameters
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
- Transaction broadcast failed: code={}, log={}
- Failed to start replacement transaction persistence: {e}
- Failed to retire replaced execution hash: {e}
- Failed to mark execution intent replaced: {e}
- Failed to record replacement transition: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/65a9d0f1389109a1.
Report an issue: GitHub.