{"record":{"id":"ca8ec006ead64870","repo":"nautechsystems/nautilus_trader","slug":"allowed-token-pair-token-in-token-out-is-no","errorCode":null,"errorMessage":"Allowed token pair {token_in} -> {token_out} is not fully pinned by the deployment manifest","messagePattern":"Allowed token pair (.+?) -> (.+?) is not fully pinned by the deployment manifest","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":446,"sourceCode":"        anyhow::ensure!(\n            token_decimals.contains_key(&weth),\n            \"Deployment manifest has no wrapped native token identity\"\n        );\n\n        if let Some(tokens) = &config.tokens {\n            for token in tokens {\n                let address = validate_address(token)?;\n                anyhow::ensure!(\n                    token_decimals.contains_key(&address),\n                    \"Configured token {address} has no deployment manifest identity\"\n                );\n            }\n        }\n\n        for (token_in, token_out) in config.allowed_token_pairs.as_deref().unwrap_or_default() {\n            let token_in = validate_address(token_in)?;\n            let token_out = validate_address(token_out)?;\n            anyhow::ensure!(\n                token_in != token_out\n                    && token_decimals.contains_key(&token_in)\n                    && token_decimals.contains_key(&token_out),\n                \"Allowed token pair {token_in} -> {token_out} is not fully pinned by the deployment manifest\"\n            );\n        }\n\n        for limit in config.quote_spend_limits.as_deref().unwrap_or_default() {\n            let spend_token = validate_address(&limit.spend_token)?;\n            anyhow::ensure!(\n                token_decimals.get(&spend_token) == Some(&limit.spend_token_decimals),\n                \"Quote spend limit decimals do not match the deployment manifest\"\n            );\n        }\n\n        let pool_contracts = role_addresses(BlockchainContractRole::Pool)?;\n\n        for pool in &manifest.pools {","sourceCodeStart":428,"sourceCodeEnd":464,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L428-L464","documentation":"During manifest validation, every configured allowed token pair must have both tokens defined in the deployment manifest's token registry (token_decimals). If either address is missing from that registry, the pair cannot be trusted for swaps and validation fails. This ensures swap routing only uses tokens explicitly pinned by the deployment manifest.","triggerScenarios":"Calling preflight/validate_manifest_contracts with config.allowed_token_pairs containing a token address that is not present in the manifest's token_decimals map, or a pair where token_in equals token_out.","commonSituations":"Operator adds a new trading pair to allowed_token_pairs but forgets to add the token (with decimals) to the deployment manifest; typo'd or checksummed-vs-lowercase address mismatch; manifest updated on another deployment.","solutions":["Add the missing token address (with correct decimals) to the deployment manifest's token registry","Remove or correct the token pair in config.allowed_token_pairs","Verify addresses are parsed consistently (same checksum format) via validate_address"],"exampleFix":"// before\nallowed_token_pairs = [[\"0xAAA...\", \"0xBBB...\"]] // 0xBBB... not in manifest tokens\n// after\n# manifest.toml\n[[tokens]]\naddress = \"0xBBB...\"\ndecimals = 6","handlingStrategy":"validation","validationCode":"// before calling preflight\nfor (tin, tout) in &config.allowed_token_pairs {\n    assert!(manifest.tokens.iter().any(|t| &t.address == tin), \"token_in {} not in manifest\", tin);\n    assert!(manifest.tokens.iter().any(|t| &t.address == tout), \"token_out {} not in manifest\", tout);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep allowed_token_pairs and manifest token registry in sync via a single source of truth","Add a CI check that validates config against the manifest","Normalize address casing before comparing"],"tags":["config","validation","blockchain","manifest"],"backgroundTag":"invalid-config-value","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}