nautechsystems/nautilus_trader · error · anyhow::Error
ratio cannot be zero
Error message
ratio cannot be zero
What it means
A spread leg ratio of zero is invalid: ratios express the hedge/multiplicity of each leg in the combo, and a zero ratio would make the leg contribute nothing while still requiring margin. The adapter bails out rather than producing a malformed spread symbol.
Source
Thrown at crates/adapters/interactive_brokers/src/common/parse.rs:1166
///
/// # 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
);
}
}
let mut sorted_ratios = leg_tuples.to_vec();
sorted_ratios.sort_by(|a, b| a.0.symbol.as_str().cmp(b.0.symbol.as_str()));
let symbol_parts = sorted_ratios
.iter()
.map(|(instrument_id, ratio)| {
if *ratio > 0 {View on GitHub (pinned to 18893faf8b)
Solutions
- Validate all leg ratios are non-zero before calling create_spread_instrument_id
- Check where leg ratios are extracted from the IB contract and fix any default-to-zero path
- Correct the ratio values at the source (IB comboLegs should carry ±1 for verticals etc.)
Example fix
// before let legs = vec![(id1, 0), (id2, 1)]; let spread = create_spread_instrument_id(&legs)?; // after let legs = vec![(id1, -1), (id2, 1)]; // short front / long back let spread = create_spread_instrument_id(&legs)?;
Defensive patterns
Strategy: validation
Validate before calling
if legs.iter().any(|(_, ratio)| *ratio == 0) { return Err(anyhow::anyhow!("zero ratio in spread legs")); } Try / catch
match create_spread_instrument_id(&legs) {
Ok(id) => id,
Err(e) if e.to_string().contains("ratio cannot be zero") => {
tracing::error!("zero leg ratio, contract data corrupt");
return Err(e);
}
Err(e) => return Err(e),
} Prevention
- Validate ratios are non-zero (typically ±1 for verticals, ±1/N for ratios) before building spreads
- Check IB comboLeg deserialization for zero-defaulting ratio fields
- Log leg tuples on failure to spot data corruption early
When it happens
Trigger: Calling create_spread_instrument_id with any (instrument_id, 0) tuple — typically from combo legs where ratio was uninitialized, defaulted to 0, or corrupted during deserialization of the IB contract.
Common situations: IB combo legs fetched with missing/zero ratio fields; hand-constructed leg tuples; data conversion bugs that zero out ratios.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- instrument_ratios list needs to have at least 2 legs
- 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/583ba2f00dd4f623.
Report an issue: GitHub.