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_in

View on GitHub (pinned to 2114cf6f76)

Solutions

  1. 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
  2. Verify the RPC URL and chain.chain_id in the client configuration match the network where the pool, router, and tokens are actually deployed
  3. Correct the address in the source of the SwapPlan (instrument definitions, router config, or strategy parameters) and retry
  4. 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

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


AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21). Data as JSON: /api/errors/0b293839fd68a1a5. Report an issue: GitHub.