nautechsystems/nautilus_trader · error · anyhow::Error
leg_contract_details must be provided
Error message
leg_contract_details must be provided
What it means
parse_spread_instrument_id builds an OptionSpread from IBKR contract details for each leg. It requires a non-empty leg_contract_details slice because it reads the first leg's contract details to derive the spread's metadata. An empty slice is a caller programming error, so it bails immediately before any parsing.
Source
Thrown at crates/adapters/interactive_brokers/src/providers/parse.rs:674
InstrumentAny::from(instrument)
}
/// Parse a spread instrument ID into an OptionSpread instrument.
///
/// This implements the same logic as Python's `parse_spread_instrument_id`.
/// Uses contract details from the first leg to determine spread properties.
///
/// # Errors
///
/// Returns an error if parsing fails.
pub fn parse_spread_instrument_id(
instrument_id: InstrumentId,
leg_contract_details: &[(&ibapi::contracts::ContractDetails, i32)],
timestamp_ns: Option<UnixNanos>,
) -> anyhow::Result<OptionSpread> {
if leg_contract_details.is_empty() {
anyhow::bail!("leg_contract_details must be provided");
}
// Use contract details from first leg
let (first_details, _) = leg_contract_details[0];
let first_contract = &first_details.contract;
// Extract properties from the first leg contract details
let currency = Currency::from(first_contract.currency.to_string());
let underlying = if !first_details.under_symbol.is_empty() {
Ustr::from(first_details.under_symbol.as_str())
} else {
Ustr::from(first_contract.symbol.as_str())
};
// Parse multiplier
let multiplier_str = first_contract.multiplier.to_string();
let multiplier =
Quantity::from_str(&multiplier_str).unwrap_or_else(|_| Quantity::new(100.0, 0)); // Default to 100 for optionsView on GitHub (pinned to 18893faf8b)
Solutions
- Ensure each spread leg's ContractDetails is fetched successfully from the IBKR client before calling the parser; retry or log failed leg requests.
- Validate leg_contract_details is non-empty at the call site and surface a domain error identifying the missing instrument instead of reaching the parser.
- If parse_option_spread_instrument_id produced empty legs, verify the instrument_id parses to a valid option spread symbol and that the contract-details lookups use the correct exchange/currency.
Example fix
// before
let legs: Vec<(&ContractDetails, i32)> = Vec::new();
let spread = parse_spread_instrument_id(instrument_id, &legs, ts)?;
// after
if legs.is_empty() {
anyhow::bail!("no contract details resolved for {instrument_id}");
}
let spread = parse_spread_instrument_id(instrument_id, &legs, ts)?; Defensive patterns
Strategy: validation
Validate before calling
if leg_contract_details.is_empty() {
return Err(anyhow::anyhow!("cannot parse spread {instrument_id}: no leg contract details"));
} Prevention
- Always await/log every leg's reqContractDetails result before parsing; fail fast per leg.
- Assert non-empty legs in unit tests for spread parsing helpers.
- Validate spread instrument_id parses into the expected number of legs before fetching details.
When it happens
Trigger: Calling parse_spread_instrument_id (directly or via parse_option_spread_instrument_id) with an empty slice of (&ContractDetails, i32) leg tuples — e.g. when the IBKR contract-details request returned nothing for all legs or the caller built the leg list without pushing any entries.
Common situations: Fetching option chain contract details returned zero matches (wrong expiry/strike filters), a bug in collecting leg details before calling the parser, or passing a default-initialized/filtered-out leg list.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Unsupported underlying type '{underlying_type}' for TRADIFI_
- Unsupported USD-M contract type '{}' for symbol '{}'
- Symbol '{}' is not trading (status: {:?})
- Unsupported COIN-M contract type '{}' for symbol '{}'
- venue_order_ids cannot be empty
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/637b9dd5c2455222.
Report an issue: GitHub.