{"record":{"id":"fb9b347b713ce329","repo":"nautechsystems/nautilus_trader","slug":"blockchain-execution-transaction-limits-are-requir","errorCode":null,"errorMessage":"Blockchain execution transaction limits are required: allowed_token_pairs, slippage_bps, max_slippage_bps, max_order_amount, deadline_seconds, max_quote_age_blocks, receipt_timeout_secs","messagePattern":"Blockchain execution transaction limits are required: allowed_token_pairs, slippage_bps, max_slippage_bps, max_order_amount, deadline_seconds, max_quote_age_blocks, receipt_timeout_secs","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":276,"sourceCode":"        let (\n            Some(allowed_token_pairs),\n            Some(slippage_bps),\n            Some(max_slippage_bps),\n            Some(max_order_amount),\n            Some(deadline_seconds),\n            Some(max_quote_age_blocks),\n            Some(receipt_timeout_secs),\n        ) = (\n            &config.allowed_token_pairs,\n            config.slippage_bps,\n            config.max_slippage_bps,\n            config.max_order_amount,\n            config.deadline_seconds,\n            config.max_quote_age_blocks,\n            config.receipt_timeout_secs,\n        )\n        else {\n            anyhow::bail!(\n                \"Blockchain execution transaction limits are required: allowed_token_pairs, slippage_bps, max_slippage_bps, max_order_amount, deadline_seconds, max_quote_age_blocks, receipt_timeout_secs\"\n            );\n        };\n\n        let mut parsed_pairs = HashSet::with_capacity(allowed_token_pairs.len());\n        for (token_in, token_out) in allowed_token_pairs {\n            parsed_pairs.insert((\n                validate_address(token_in.as_str())?,\n                validate_address(token_out.as_str())?,\n            ));\n        }\n\n        let quote_spend_limits = config.quote_spend_limits.as_deref().unwrap_or_default();\n        let mut parsed_quote_spend_limits = HashMap::with_capacity(quote_spend_limits.len());\n        for limit in quote_spend_limits {\n            let token_in = validate_address(limit.token_in.as_str())?;\n            let token_out = validate_address(limit.token_out.as_str())?;\n            let spend_token = validate_address(limit.spend_token.as_str())?;","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L258-L294","documentation":"transaction_limits() requires a fully populated set of execution risk limits. If any of allowed_token_pairs, slippage_bps, max_slippage_bps, max_order_amount, deadline_seconds, max_quote_age_blocks, or receipt_timeout_secs is absent from the config, the else-branch of the destructuring let bails with this message enumerating all required fields.","triggerScenarios":"Calling BlockchainExecutionClient::new (which invokes transaction_limits) with a config where any one of the seven required limit fields is None/missing.","commonSituations":"Upgrading to a version that added new mandatory fields (e.g. receipt_timeout_secs) while reusing an old config file; hand-written config omitting optional-looking fields; a config parser that maps missing TOML keys to None silently.","solutions":["Populate all seven listed fields in the config: allowed_token_pairs, slippage_bps, max_slippage_bps, max_order_amount, deadline_seconds, max_quote_age_blocks, receipt_timeout_secs","Diff the config against the current ExecutionClientConfig struct to find newly required fields","Check release notes for config schema changes after an upgrade"],"exampleFix":"// before\n[execution]\nslippage_bps = 50\n// after\n[execution]\nallowed_token_pairs = [[\"0x...IN\", \"0x...OUT\"]]\nslippage_bps = 50\nmax_slippage_bps = 200\nmax_order_amount = \"1000000000000000000\"\ndeadline_seconds = 120\nmax_quote_age_blocks = 10\nreceipt_timeout_secs = 60","handlingStrategy":"validation","validationCode":"let required = [\n    (\"allowed_token_pairs\", cfg.allowed_token_pairs.is_none()),\n    (\"slippage_bps\", cfg.slippage_bps.is_none()),\n    (\"max_slippage_bps\", cfg.max_slippage_bps.is_none()),\n    (\"max_order_amount\", cfg.max_order_amount.is_none()),\n    (\"deadline_seconds\", cfg.deadline_seconds.is_none()),\n    (\"max_quote_age_blocks\", cfg.max_quote_age_blocks.is_none()),\n    (\"receipt_timeout_secs\", cfg.receipt_timeout_secs.is_none()),\n];\nlet missing: Vec<_> = required.iter().filter(|(_, m)| *m).map(|(n, _)| *n).collect();\nif !missing.is_empty() { panic!(\"missing execution limit fields: {missing:?}\"); }","typeGuard":null,"tryCatchPattern":"match BlockchainExecutionClient::new(config, provider).await {\n    Err(e) if e.to_string().contains(\"transaction limits are required\") => {\n        // surface missing-field list to the operator, abort startup\n    }\n    Err(e) => return Err(e),\n    Ok(client) => client,\n}","preventionTips":["Use serde deny_unknown_fields + explicit non-Option types so missing keys fail at deserialization","Version the config schema and validate on upgrade","Write a startup integration test that constructs the client from the real config"],"tags":["config","validation","missing-fields"],"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-23T08:17:48.524Z"}