nautechsystems/nautilus_trader · error
`router_addresses` must contain at least one router address
Error message
`router_addresses` must contain at least one router address
What it means
BlockchainExecutionClient::new validates the router_addresses list from the config before constructing the client. The library throws this when the configured router address collection is empty, because an execution client cannot route swaps without at least one Uniswap-style router contract. Fail-fast happens at construction rather than at first transaction.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:210
http_rpc_client.clone(),
config.http_rpc_url.expose_secret(),
verification_config,
config.rpc_requests_per_second,
)?;
let wallet_address = validate_address(config.wallet_address.as_str())?;
let erc20_contract = Erc20Contract::new_with_timeout(
http_rpc_client.clone(),
Some(EXECUTION_RPC_TIMEOUT_SECS),
true,
);
let router_addresses = config
.router_addresses
.iter()
.map(|address| validate_address(address.as_str()))
.collect::<anyhow::Result<Vec<_>>>()?;
if router_addresses.is_empty() {
anyhow::bail!("`router_addresses` must contain at least one router address");
}
let weth_address = validate_address(config.weth_address.as_str())?;
Self::validate_manifest_contracts(&config, &router_addresses, weth_address)?;
let mut token_universe = HashSet::new();
if let Some(specified_tokens) = &config.tokens {
for token in specified_tokens {
let token_address = validate_address(token.as_str())?;
token_universe.insert(token_address);
}
}
let wallet_balance = WalletBalance::new(token_universe);
let emitter = ExecutionEventEmitter::new(
get_atomic_clock_realtime(),
core_client.trader_id,
core_client.account_id,
core_client.account_type,View on GitHub (pinned to 18893faf8b)
Solutions
- Add at least one valid router address to config.router_addresses for the target chain
- Verify the config loader is actually populating router_addresses (no silent default to empty vec)
- Confirm the addresses belong to the connected network and are checksummed/parseable by validate_address
Example fix
// before router_addresses = [] // after router_addresses = ["0xE592427A0AEce92De3Edee1F18E0157C05861564"]
Defensive patterns
Strategy: validation
Validate before calling
if config.router_addresses.is_empty() {
return Err("router_addresses must contain at least one address before constructing the client".into());
}
for a in &config.router_addresses {
Address::from_str(a)?; // also fails fast on malformed addresses
} Type guard
fn has_router_addresses(cfg: &ExecutionClientConfig) -> bool {
!cfg.router_addresses.is_empty()
} Prevention
- Template the per-chain config with a non-empty router_addresses default
- Validate the full config with a dry-run constructor or unit test in CI
- Keep router addresses keyed by chain id in one shared config module
When it happens
Trigger: Calling BlockchainExecutionClient::new (public) with a config whose router_addresses vec/field is empty or omitted, e.g. an unset TOML/env config mapping to Vec::new().
Common situations: Config file missing the router_addresses section; a defaults-loading layer skipping empty lists; operator forgetting to set router addresses per-chain when switching networks.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Quote spend limit for {token_in} -> {token_out} is denominat
- Independent Blockchain execution verification is required
- Verification chain anchor ID does not match the configured c
- Verification chain anchor name does not match the configured
- Allowed token pair {token_in} -> {token_out} is not fully pi
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/3cb4c2e0d2639e14.
Report an issue: GitHub.