nautechsystems/nautilus_trader · error · anyhow::Error

Deployment manifest must contain exactly one {description} c

Error message

Deployment manifest must contain exactly one {description} contract

What it means

`validate_manifest_contracts` builds a `singleton` helper that resolves a contract role to exactly one address. When the set of addresses for a given role in the deployment manifest does not have length exactly 1 (zero entries or more than one), `anyhow::ensure!` fails with this message naming the role's description (e.g. 'wrapped native', 'factory', 'quote'). Singleton roles must appear exactly once in the manifest.

Source

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

    ) -> anyhow::Result<()> {
        let verification = config.verification.as_ref().ok_or_else(|| {
            anyhow::anyhow!("Independent Blockchain execution verification is required")
        })?;
        let manifest = &verification.deployment_manifest;
        let role_addresses = |role| {
            manifest
                .contracts
                .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)

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure the manifest contains exactly one `contracts` entry with the required role (factory, quote, or wrapped native)
  2. Remove duplicate contracts entries that share the same role
  3. Regenerate the manifest for the target chain so all singleton roles are present exactly once

Example fix

// before: two factory entries
{"role": "Factory", "address": "0xAAA..."},
{"role": "Factory", "address": "0xBBB..."}
// after: exactly one
{"role": "Factory", "address": "0xAAA..."}
Defensive patterns

Strategy: validation

Validate before calling

fn check_singletons(contracts: &[ContractEntry], role: BlockchainContractRole) -> Result<(), String> {
    let n = contracts.iter().filter(|c| c.role == role).count();
    if n != 1 { Err(format!("role {role:?} appears {n} times, expected 1")) } else { Ok(()) }
}

Try / catch

match result { Err(e) if e.to_string().contains("exactly one") => { /* fix manifest: add/remove duplicate role entry */ }, Err(e) => return Err(e), Ok(v) => v }

Prevention

When it happens

Trigger: Running client validation where `manifest.contracts` contains no contract with the requested `BlockchainContractRole`, or contains multiple contracts sharing that role (duplicate factory/router-family entries), or a `description` placeholder renders the role name into the message.

Common situations: Merging two deployment manifests and keeping both factory entries; deleting the Quote contract entry when trimming the manifest; forgetting to add the WrappedNative contract for a new chain; a misconfigured `role` field meaning the expected role is missing while another role has duplicates.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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