nautechsystems/nautilus_trader · error
No deployed bytecode at {description} address {address}
Error message
No deployed bytecode at {description} address {address} What it means
Thrown by check_swap_preconditions before any swap transaction is signed. The client calls eth_getCode for each address in the SwapPlan (pool, router, input token, output token) and requires non-empty bytecode, proving each is a deployed contract on the chain served by the configured RPC. An empty result means the address is an externally owned account (EOA) or simply does not exist, so the swap would fail or send funds to nowhere.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:2401
}
/// Runs the read-only pre-trade checks for a swap: deployed bytecode at the pool, router,
/// and token addresses, and an operator-prepared router allowance and input-token balance
/// covering the amount. The shared signing pipeline checks the exact maximum native cost.
/// Never wraps or approves.
async fn check_swap_preconditions(
plan: &SwapPlan,
executor: &TransactionExecutor,
) -> anyhow::Result<()> {
for (address, description) in [
(plan.pool_address, "pool"),
(plan.router, "router"),
(plan.token_in, "input token"),
(plan.token_out, "output token"),
] {
let code = executor.http_rpc_client.get_code(&address).await?;
if code.is_empty() {
anyhow::bail!("No deployed bytecode at {description} address {address}");
}
}
let erc20_contract = Erc20Contract::new_with_timeout(
executor.http_rpc_client.clone(),
Some(EXECUTION_RPC_TIMEOUT_SECS),
true,
);
let allowance = erc20_contract
.allowance(&plan.token_in, &executor.wallet_address, &plan.router)
.await?;
if allowance < plan.amount_in {
anyhow::bail!(
"Router allowance {allowance} is below the swap amount {} for input token {}; approve the router explicitly before submitting",
plan.amount_in,
plan.token_inView on GitHub (pinned to 2114cf6f76)
Solutions
- Look up each address named in the error on a block explorer for the SAME chain the RPC serves; the failing one will show no contract code
- Verify the RPC URL and chain.chain_id in the client configuration match the network where the pool, router, and tokens are actually deployed
- Correct the address in the source of the SwapPlan (instrument definitions, router config, or strategy parameters) and retry
- If a contract genuinely is not deployed yet (e.g. custom router), deploy it before submitting swaps
Example fix
// before: chain_id = 1 (Ethereum mainnet) but RPC is Sepolia and
// plan.router is a mainnet deployment
let config = BlockchainExecutionConfig { chain_rpc_http: "https://sepolia.infura.io/v3/...".into(), /* chain = Sepolia */ .. };
// after: keep addresses and chain consistent
// mainnet addresses only with a mainnet RPC and chain_id = 1
let config = BlockchainExecutionConfig { chain_rpc_http: "https://mainnet.infura.io/v3/...".into(), .. }; Defensive patterns
Strategy: validation
Validate before calling
// Before building/executing a SwapPlan, prove each address is a contract on this chain
async fn all_addresses_are_contracts(rpc: &HttpRpcClient, addrs: &[(&Address, &str)]) -> anyhow::Result<bool> {
for (addr, desc) in addrs {
if rpc.get_code(addr).await?.is_empty() {
log::warn!("{desc} address {addr} has no bytecode");
return Ok(false);
}
}
Ok(true)
} Type guard
fn is_non_empty_code(code: &[u8]) -> bool { !code.is_empty() } Try / catch
// check_swap_preconditions already runs pre-signature; treat its Err as terminal for this
// plan: log the failing address, surface to the operator, and do NOT retry the same plan.
if let Err(e) = execute_swap(plan).await {
if e.to_string().contains("No deployed bytecode") {
// config/address bug — fix data, never re-submit unchanged
alert_operator(&e.to_string());
}
return Err(e);
} Prevention
- Keep RPC URL, chain id, and all contract addresses in one per-environment config block
- Add a startup smoke test that eth_getCode's every configured pool/router/token
- Cross-check addresses against a block explorer for the exact chain before first run
When it happens
Trigger: Calling submit/execute of the blockchain execution client with a SwapPlan whose pool_address, router, token_in, or token_out is a mistyped address, an EOA, or a contract that is not deployed on the connected chain (e.g. a mainnet Uniswap pool address used against a Sepolia RPC). Any one of the four get_code calls returning empty triggers the bail.
Common situations: RPC URL and chain configuration disagree (testnet RPC with mainnet addresses), copy/paste typo in a token or router address, a deprecated or migrated router address, tokens without real contracts (scam/fake tokens), or an instrument definition carrying an address for the wrong chain fork.
Related errors
- No pool profiler for {instrument_id}; an active data subscri
- Blockchain execution transaction limits are required: allowe
- Finalized block {} does not contain transaction {}
- Router allowance {allowance} is below the swap amount {} for
- Input token {} balance {balance} is below the swap amount {}
AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21).
Data as JSON: /api/errors/0b293839fd68a1a5.
Report an issue: GitHub.