nautechsystems/nautilus_trader · error · anyhow::Error

Deployment manifest contains a duplicate token identity

Error message

Deployment manifest contains a duplicate token identity

What it means

When populating `token_decimals`, the validator uses `HashMap::insert` and `anyhow::ensure!(insert(...).is_none(), ...)` to reject any address that appears more than once in `manifest.tokens`. This error means two token entries share the same address, so the manifest's token identity set is not unique and decimals would be ambiguous.

Source

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

                .map(|dex| dex.factory)
                .ok_or_else(|| {
                    anyhow::anyhow!(
                        "No registered Uniswap V3 deployment for chain {}",
                        config.chain.name
                    )
                })?;
        anyhow::ensure!(
            factory == registered_factory,
            "Deployment manifest factory does not match the registered Uniswap V3 factory"
        );
        let quote_contract = singleton(BlockchainContractRole::Quote, "quote")?;

        let mut token_decimals = HashMap::new();

        for token in &manifest.tokens {
            let address = Address::from_str(&token.address)
                .map_err(|_| anyhow::anyhow!("Deployment manifest token address is invalid"))?;
            anyhow::ensure!(
                token_decimals.insert(address, token.decimals).is_none(),
                "Deployment manifest contains a duplicate token identity"
            );
        }
        anyhow::ensure!(
            token_decimals.contains_key(&weth),
            "Deployment manifest has no wrapped native token identity"
        );

        if let Some(tokens) = &config.tokens {
            for token in tokens {
                let address = validate_address(token)?;
                anyhow::ensure!(
                    token_decimals.contains_key(&address),
                    "Configured token {address} has no deployment manifest identity"
                );
            }
        }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Remove the duplicate `tokens` entry so each address appears exactly once in the manifest
  2. If both entries were intentional aliases, keep one canonical entry per contract address
  3. Regenerate the manifest token list to deduplicate

Example fix

// before
{"symbol": "USDC", "address": "0xA0b8...eB48"},
{"symbol": "USDC_OLD", "address": "0xA0b8...eB48"}
// after
{"symbol": "USDC", "address": "0xA0b8...eB48"}
Defensive patterns

Strategy: validation

Validate before calling

let mut seen = HashSet::new();
for t in &manifest.tokens {
    let a = Address::from_str(&t.address).unwrap();
    if !seen.insert(a) { return Err(format!("duplicate token address {a}")); }
}

Prevention

When it happens

Trigger: Client validation where `manifest.tokens` contains two entries whose parsed `Address` is equal — exact duplicate rows, or the same address listed under two different symbols/decimals.

Common situations: Appending a token to the manifest that already exists (merge conflict or script rerun); listing the same contract under wrapped and unwrapped names; copy-paste duplicating a token block with an edited symbol but unchanged address.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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