nautechsystems/nautilus_trader · error · anyhow::Error

Deployment manifest router set does not match `router_addres

Error message

Deployment manifest router set does not match `router_addresses`

What it means

After collecting all `Router`-role addresses from the deployment manifest, `validate_manifest_contracts` compares that set against the router addresses configured in the client config (`router_addresses`). `anyhow::ensure!` fails when the two `HashSet`s differ — meaning the manifest and the explicit config disagree on which router contracts to use.

Source

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

                .iter()
                .filter(|contract| contract.role == role)
                .map(|contract| {
                    Address::from_str(&contract.address)
                        .map_err(|_| anyhow::anyhow!("Deployment manifest address is invalid"))
                })
                .collect::<anyhow::Result<HashSet<_>>>()
        };
        let singleton = |role, description: &str| {
            let addresses = role_addresses(role)?;
            anyhow::ensure!(
                addresses.len() == 1,
                "Deployment manifest must contain exactly one {description} contract"
            );
            Ok(*addresses.iter().next().expect("singleton role address"))
        };

        let configured_routers = routers.iter().copied().collect::<HashSet<_>>();
        anyhow::ensure!(
            role_addresses(BlockchainContractRole::Router)? == configured_routers,
            "Deployment manifest router set does not match `router_addresses`"
        );
        anyhow::ensure!(
            singleton(BlockchainContractRole::WrappedNative, "wrapped native")? == weth,
            "Deployment manifest wrapped native contract does not match `weth_address`"
        );
        let factory = singleton(BlockchainContractRole::Factory, "factory")?;
        let registered_factory =
            crate::exchanges::get_dex_extended(config.chain.name, &DexType::UniswapV3)
                .map(|dex| dex.factory)
                .ok_or_else(|| {
                    anyhow::anyhow!(
                        "No registered Uniswap V3 deployment for chain {}",
                        config.chain.name
                    )
                })?;
        anyhow::ensure!(

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Make the `Router` entries in the deployment manifest exactly match the `router_addresses` set in the client config
  2. Regenerate the deployment manifest from the same deployment that produced the configured router addresses
  3. If the router list changed intentionally, update both config and manifest together

Example fix

// before (config) — manifest has only router A
router_addresses: [routerA, routerB]
// after
router_addresses: [routerA]  // or add routerB to the manifest
Defensive patterns

Strategy: validation

Validate before calling

let manifest_routers: HashSet<Address> = manifest.contracts.iter()
    .filter(|c| c.role == BlockchainContractRole::Router)
    .filter_map(|c| Address::from_str(&c.address).ok())
    .collect();
let configured: HashSet<Address> = config.router_addresses.iter().copied().collect();
assert_eq!(manifest_routers, configured, "router set mismatch between manifest and config");

Prevention

When it happens

Trigger: Initializing the execution client when `manifest.contracts` with role `Router` yields a different address set than the `routers` argument passed to `validate_manifest_contracts` (extra routers in one side, missing in the other, or a different address entirely).

Common situations: Updating `router_addresses` in config after a router upgrade without regenerating the manifest; pointing config at a different deployment than the manifest file; adding an additional router to config but not the manifest; checksummed vs lowercase rendering of the same address producing unequal `Address` values is not possible here (parsed to `Address`), so mismatches are genuinely different sets.

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