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(
"e_token.symbol,
quote_token.decimals,
0,
"e_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
- Add the exact (token_in, token_out) pair to `allowed_token_pairs` in the transaction_limits configuration.
- Check address ordering — add the pair in the same direction the order resolves, or add both directions if either direction is tradable.
- 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
- Keep allowed_token_pairs in sync whenever instruments are added.
- Add both directions of a pair if either is tradable.
- Validate token addresses (checksum/case) against on-chain values during config load.
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
- Order amount {base_amount} exceeds the configured `max_order
- Slippage {slippage_bps} bps exceeds the configured `max_slip
- No quote spend ceiling for BUY token pair {} -> {}
- Chain ID mismatch at connect: expected {expected_chain_id},
- Unsupported blockchain {blockchain} for RPC connection
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/b98b7b18dde63954.
Report an issue: GitHub.