nautechsystems/nautilus_trader · error
Blockchain execution transaction limits are required…
Error message
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
What it means
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.
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
Example fix
// before [execution] slippage_bps = 50 // after [execution] allowed_token_pairs = [["0x...IN", "0x...OUT"]] slippage_bps = 50 max_slippage_bps = 200 max_order_amount = "1000000000000000000" deadline_seconds = 120 max_quote_age_blocks = 10 receipt_timeout_secs = 60
Defensive patterns
Strategy: validation
Validate before calling
let required = [
("allowed_token_pairs", cfg.allowed_token_pairs.is_none()),
("slippage_bps", cfg.slippage_bps.is_none()),
("max_slippage_bps", cfg.max_slippage_bps.is_none()),
("max_order_amount", cfg.max_order_amount.is_none()),
("deadline_seconds", cfg.deadline_seconds.is_none()),
("max_quote_age_blocks", cfg.max_quote_age_blocks.is_none()),
("receipt_timeout_secs", cfg.receipt_timeout_secs.is_none()),
];
let missing: Vec<_> = required.iter().filter(|(_, m)| *m).map(|(n, _)| *n).collect();
if !missing.is_empty() { panic!("missing execution limit fields: {missing:?}"); } Try / catch
match BlockchainExecutionClient::new(config, provider).await {
Err(e) if e.to_string().contains("transaction limits are required") => {
// surface missing-field list to the operator, abort startup
}
Err(e) => return Err(e),
Ok(client) => client,
} Prevention
- 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
When it happens
Trigger: Calling BlockchainExecutionClient::new (which invokes transaction_limits) with a config where any one of the seven required limit fields is None/missing.
Common situations: 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.
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.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Allowed token pair -> is not fully pinned by the deployment…
- Binance instrument filter
- Binance load_ids value
- Binance US market data requires spot_market_data_mode=Json
- Binance US supports Spot clients only
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/fb9b347b713ce329.
Report an issue: GitHub.
Appendix: source
Thrown at crates/adapters/blockchain/src/execution/client.rs:276
let (
Some(allowed_token_pairs),
Some(slippage_bps),
Some(max_slippage_bps),
Some(max_order_amount),
Some(deadline_seconds),
Some(max_quote_age_blocks),
Some(receipt_timeout_secs),
) = (
&config.allowed_token_pairs,
config.slippage_bps,
config.max_slippage_bps,
config.max_order_amount,
config.deadline_seconds,
config.max_quote_age_blocks,
config.receipt_timeout_secs,
)
else {
anyhow::bail!(
"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"
);
};
let mut parsed_pairs = HashSet::with_capacity(allowed_token_pairs.len());
for (token_in, token_out) in allowed_token_pairs {
parsed_pairs.insert((
validate_address(token_in.as_str())?,
validate_address(token_out.as_str())?,
));
}
let quote_spend_limits = config.quote_spend_limits.as_deref().unwrap_or_default();
let mut parsed_quote_spend_limits = HashMap::with_capacity(quote_spend_limits.len());
for limit in quote_spend_limits {
let token_in = validate_address(limit.token_in.as_str())?;
let token_out = validate_address(limit.token_out.as_str())?;
let spend_token = validate_address(limit.spend_token.as_str())?;View on GitHub (pinned to 18893faf8b)