nautechsystems/nautilus_trader · error · anyhow::Error
instrument_ratios list needs to have at least 2 legs
Error message
instrument_ratios list needs to have at least 2 legs
What it means
create_spread_instrument_id builds a spread (combo/bag) instrument ID from a list of (InstrumentId, ratio) legs and requires at least two legs; a single-leg 'spread' is meaningless so the call fails fast.
Source
Thrown at crates/adapters/interactive_brokers/src/common/parse.rs:1159
///
/// This implements the same logic as Python's `InstrumentId.new_spread`:
/// - Creates a symbol string like `(1)SYMBOL1_((2))SYMBOL2`
/// - Positive ratios: `(ratio)SYMBOL`
/// - Negative ratios: `((abs(ratio)))SYMBOL`
/// - Sorts legs alphabetically by symbol
/// - All legs must have the same venue
///
/// # Errors
///
/// Returns an error if:
/// - Less than 2 legs provided
/// - Any ratio is zero
/// - Venues don't match across legs
pub fn create_spread_instrument_id(
leg_tuples: &[(InstrumentId, i32)],
) -> anyhow::Result<InstrumentId> {
if leg_tuples.len() < 2 {
anyhow::bail!("instrument_ratios list needs to have at least 2 legs");
}
let first_venue = leg_tuples[0].0.venue;
for (instrument_id, ratio) in leg_tuples {
if *ratio == 0 {
anyhow::bail!("ratio cannot be zero");
}
if instrument_id.venue != first_venue {
anyhow::bail!(
"All venues must match. Expected {}, was {}",
first_venue,
instrument_id.venue
);
}
}
View on GitHub (pinned to 18893faf8b)
Solutions
- Verify the source contract has >= 2 combo legs before constructing the spread instrument ID
- Check that leg extraction from the IB BAG contract is not dropping legs (filters, leg type checks)
- Guard the call site: skip single/zero-leg bags instead of attempting to build a spread ID
Example fix
// before
let id = create_spread_instrument_id(&legs)?;
// after
if legs.len() < 2 {
tracing::warn!("BAG contract has <2 legs, skipping");
return Ok(None);
}
let id = create_spread_instrument_id(&legs)?; Defensive patterns
Strategy: validation
Validate before calling
if legs.len() < 2 { return Err(anyhow::anyhow!("spread needs >= 2 legs")); } Try / catch
match create_spread_instrument_id(&legs) {
Ok(id) => id,
Err(e) if e.to_string().contains("at least 2 legs") => {
tracing::warn!("bag has insufficient legs ({})", legs.len());
return Ok(None);
}
Err(e) => return Err(e),
} Prevention
- Validate combo leg count before constructing spread IDs
- Log raw IB comboLegs when a BAG yields <2 legs to catch extraction bugs
- Treat single-leg bags as invalid data and skip them
When it happens
Trigger: Calling create_spread_instrument_id (directly or via resolve_spread_instrument_id_for_contract / fetch_bag_contract) with an empty or one-element slice, e.g. when cached combo legs for a BAG contract contain only one leg or the legs list failed to populate.
Common situations: Parsing IB BAG contracts whose comboLegs were truncated or only partially received; building a spread instrument from a single leg due to a filtering bug or cache miss.
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
- ratio cannot be zero
- All venues must match. Expected {}, was {}
- Invalid spread symbol format for component: {component}
- Timeout must be greater than 0
- Timeout must be less than 3600 seconds
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/db3f133e652eedc6.
Report an issue: GitHub.