nautechsystems/nautilus_trader · error

Router {router} is not in the configured `router_addresses`

Error message

Router {router} is not in the configured `router_addresses` allowlist

What it means

BlockchainExecutionClient::approve rejects any ERC-20 approval whose spender (router) address is not present in the client's configured `router_addresses` allowlist. This is a deliberate policy guard: the adapter only ever grants spending allowance to explicitly vetted router contracts, preventing token approvals to unexpected or malicious contracts. If the router address passed to approve() is not exactly listed in the configuration, the call bails before any transaction is built.

Source

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

    ///
    /// This is an explicit operator operation; it never runs inside `submit_order`.
    ///
    /// # Errors
    ///
    /// Returns an error if the router or token fails policy and deployment checks, a nonzero
    /// allowance was not cleared first, approval simulation returns false or malformed data, the
    /// client is not connected, another transaction is in flight, no durable store is configured,
    /// the resulting allowance differs from the target, or any RPC, signing, persistence, or
    /// broadcast step fails. A persistence failure after signing, or a failed postcondition after
    /// finality, leaves the in-flight slot occupied.
    pub async fn approve(
        &mut self,
        token: Address,
        amount: U256,
        router: Address,
    ) -> anyhow::Result<B256> {
        if !self.router_addresses.contains(&router) {
            anyhow::bail!("Router {router} is not in the configured `router_addresses` allowlist");
        }

        if !amount.is_zero()
            && !self
                .transaction_limits
                .allowed_token_pairs
                .iter()
                .any(|(token_in, _)| *token_in == token)
        {
            anyhow::bail!(
                "Token {token} is not an input token in the configured `allowed_token_pairs`"
            );
        }

        self.ensure_transaction_ready(TransactionPurpose::Approve)?;

        let approval_amount = if amount.is_zero() {
            U256::ZERO

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Add the router address actually being used to the `router_addresses` allowlist in the client/blockchain adapter configuration, then restart the client.
  2. Verify the router address matches the deployment for the target chain (e.g. Uniswap V3 SwapRouter02 vs SwapRouter) and that you are connected to the intended chain.
  3. If the router is unexpected, audit where it came from: a swap plan or venue config may be passing a stale or wrong router to approve(); fix the caller to use a router from the registry/config instead.

Example fix

// before: router hardcoded, not in config
let router: Address = "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45".parse()?;
client.approve(token, amount, router).await?;

// after: reuse a router address from the configured allowlist
let router = client.config.router_addresses.first().copied()
    .context("no routers configured")?;
client.approve(token, amount, router).await?;
Defensive patterns

Strategy: validation

Validate before calling

let router: Address = router_addr.parse()?;
if !client.router_addresses.contains(&router) {
    anyhow::bail!("router {router} is not allowlisted; update router_addresses config");
}
// safe to call client.approve(token, amount, router).await?

Type guard

fn is_allowlisted_router(router: Address, allowlist: &[Address]) -> bool {
    allowlist.contains(&router)
}

Try / catch

match client.approve(token, amount, router).await {
    Ok(tx_hash) => info!(%tx_hash, "approval confirmed"),
    Err(e) if e.to_string().contains("router_addresses") => {
        error!("router not in allowlist — fix config, do not retry");
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling `client.approve(token, amount, router)` where `router` is not an exact member of `self.router_addresses` (the allowlist supplied at client construction / config). Also triggered by case-sensitive mismatch: the check uses Address equality, so a differently checksummed-but-same address still matches (Address normalizes), but a genuinely different router deployment (e.g. a V3 vs V2 router, or a router on another chain) will fail.

Common situations: Configuring `router_addresses` for one chain but approving on another; using a Uniswap V2 router with a V3-only allowlist (or vice versa); hardcoding a router from a mainnet deployment while running against a testnet; adding a new swap venue to the strategy without updating the allowlist; typos or stale checksummed hex in the config.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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