nautechsystems/nautilus_trader · error

Token pair {token_in} -> {token_out} is not in the `allowed_

Error message

Token pair {token_in} -> {token_out} is not in the `allowed_token_pairs` allowlist

What it means

The client enforces a configured `allowed_token_pairs` allowlist; submitting a swap whose (token_in, token_out) pair is not in that list is rejected as a safety control against trading unintended tokens. The pair is checked after resolving the pool and computing direction.

Source

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

        let base_token = pool.get_base_token();
        let quote_token = pool.get_quote_token();
        let quote_currency = Currency::new_checked(
            &quote_token.symbol,
            quote_token.decimals,
            0,
            &quote_token.name,
            CurrencyType::Crypto,
        )?;
        let (token_in, token_out) =
            swap_token_pair(order.order_side(), base_token.address, quote_token.address)?;

        if !self
            .transaction_limits
            .allowed_token_pairs
            .contains(&(token_in, token_out))
        {
            anyhow::bail!(
                "Token pair {token_in} -> {token_out} is not in the `allowed_token_pairs` allowlist"
            );
        }

        let base_amount = quantity_to_raw_amount(order.quantity(), base_token.decimals)?;
        if base_amount > U256::from(self.transaction_limits.max_order_amount) {
            anyhow::bail!(
                "Order amount {base_amount} exceeds the configured `max_order_amount` {}",
                self.transaction_limits.max_order_amount
            );
        }

        let slippage_bps = match cmd
            .params
            .as_ref()
            .and_then(|params| params.get_u64("slippage_bps"))
        {
            Some(value) => u32::try_from(value).map_err(|_| {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Add the exact (token_in, token_out) pair to `allowed_token_pairs` in the transaction_limits configuration.
  2. Check address ordering — add the pair in the same direction the order resolves, or add both directions if either direction is tradable.
  3. Verify the token addresses in the config match the on-chain token addresses (checksummed/lowercase consistently).

Example fix

// before
transaction_limits.allowed_token_pairs = vec![(usdc_addr, weth_addr)];
// after
transaction_limits.allowed_token_pairs = vec![
    (usdc_addr, weth_addr),
    (weth_addr, usdc_addr), // allow the reverse direction too
];
Defensive patterns

Strategy: validation

Validate before calling

// Rust
let pair = (token_in_addr, token_out_addr);
if !transaction_limits.allowed_token_pairs.contains(&pair) {
    return Err(anyhow::anyhow!("pair {:?} not allowlisted", pair));
}

Prevention

When it happens

Trigger: submit_order for an instrument whose base/quote tokens are not both present in transaction_limits.allowed_token_pairs — e.g. trading a new pool that was never added to the allowlist config.

Common situations: Adding a new pool/instrument to the strategy but forgetting to update the allowlist; token address ordering mismatch (allowlist stores (tokenA,tokenB) but the order resolves to (tokenB,tokenA)); typos in token addresses in the config file.

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/b98b7b18dde63954. Report an issue: GitHub.