{"record":{"id":"f85d50302fbe5689","repo":"nautechsystems/nautilus_trader","slug":"deployment-manifest-must-contain-exactly-one-desc","errorCode":null,"errorMessage":"Deployment manifest must contain exactly one {description} contract","messagePattern":"Deployment manifest must contain exactly one (.+?) contract","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":386,"sourceCode":"    ) -> anyhow::Result<()> {\n        let verification = config.verification.as_ref().ok_or_else(|| {\n            anyhow::anyhow!(\"Independent Blockchain execution verification is required\")\n        })?;\n        let manifest = &verification.deployment_manifest;\n        let role_addresses = |role| {\n            manifest\n                .contracts\n                .iter()\n                .filter(|contract| contract.role == role)\n                .map(|contract| {\n                    Address::from_str(&contract.address)\n                        .map_err(|_| anyhow::anyhow!(\"Deployment manifest address is invalid\"))\n                })\n                .collect::<anyhow::Result<HashSet<_>>>()\n        };\n        let singleton = |role, description: &str| {\n            let addresses = role_addresses(role)?;\n            anyhow::ensure!(\n                addresses.len() == 1,\n                \"Deployment manifest must contain exactly one {description} contract\"\n            );\n            Ok(*addresses.iter().next().expect(\"singleton role address\"))\n        };\n\n        let configured_routers = routers.iter().copied().collect::<HashSet<_>>();\n        anyhow::ensure!(\n            role_addresses(BlockchainContractRole::Router)? == configured_routers,\n            \"Deployment manifest router set does not match `router_addresses`\"\n        );\n        anyhow::ensure!(\n            singleton(BlockchainContractRole::WrappedNative, \"wrapped native\")? == weth,\n            \"Deployment manifest wrapped native contract does not match `weth_address`\"\n        );\n        let factory = singleton(BlockchainContractRole::Factory, \"factory\")?;\n        let registered_factory =\n            crate::exchanges::get_dex_extended(config.chain.name, &DexType::UniswapV3)","sourceCodeStart":368,"sourceCodeEnd":404,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L368-L404","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure the manifest contains exactly one `contracts` entry with the required role (factory, quote, or wrapped native)","Remove duplicate contracts entries that share the same role","Regenerate the manifest for the target chain so all singleton roles are present exactly once"],"exampleFix":"// before: two factory entries\n{\"role\": \"Factory\", \"address\": \"0xAAA...\"},\n{\"role\": \"Factory\", \"address\": \"0xBBB...\"}\n// after: exactly one\n{\"role\": \"Factory\", \"address\": \"0xAAA...\"}","handlingStrategy":"validation","validationCode":"fn check_singletons(contracts: &[ContractEntry], role: BlockchainContractRole) -> Result<(), String> {\n    let n = contracts.iter().filter(|c| c.role == role).count();\n    if n != 1 { Err(format!(\"role {role:?} appears {n} times, expected 1\")) } else { Ok(()) }\n}","typeGuard":null,"tryCatchPattern":"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 }","preventionTips":["After editing a manifest, count entries per role and assert exactly one factory/quote/wrapped-native","Never merge manifests for the same chain without deduplicating roles","Use a JSON schema that enforces unique roles"],"tags":["rust","config","validation","ethereum"],"backgroundTag":"missing-required-config-field","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}