nautechsystems/nautilus_trader · error · anyhow::Error
All venues must match. Expected {}, was {}
Error message
All venues must match. Expected {}, was {} What it means
All legs of a spread must belong to the same venue because the resulting spread InstrumentId encodes a single venue; mixed venues cannot be represented. The error names the expected (first leg's) venue and the mismatching leg's venue.
Source
Thrown at crates/adapters/interactive_brokers/src/common/parse.rs:1170
/// - 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 {
format!("({}){}", ratio, instrument_id.symbol.as_str())
} else {
format!("(({})){}", ratio.abs(), instrument_id.symbol.as_str())
}View on GitHub (pinned to 18893faf8b)
Solutions
- Ensure every leg InstrumentId uses the same venue suffix before building the spread
- Fix the venue assignment when constructing leg InstrumentIds (e.g. wrong exchange mapping)
- Filter out legs from other venues instead of mixing them
Example fix
// before
let legs = vec![(InstrumentId::from("AAPL 251212C00250000.OPRA"), -1),
(InstrumentId::from("MSFT 251212P00400000.OPRA"), 1)]; // venue must match, MSFT leg wrong here
// after
let legs = vec![(InstrumentId::from("AAPL 251212C00250000.OPRA"), -1),
(InstrumentId::from("AAPL 251212P00250000.OPRA"), 1)]; Defensive patterns
Strategy: validation
Validate before calling
let first = legs.first().map(|(id, _)| id.venue);
if legs.iter().any(|(id, _)| Some(id.venue) != first) {
return Err(anyhow::anyhow!("spread legs span multiple venues"));
} Try / catch
match create_spread_instrument_id(&legs) {
Ok(id) => id,
Err(e) if e.to_string().contains("All venues must match") => {
tracing::error!("mixed-venue legs: {e}");
return Err(e);
}
Err(e) => return Err(e),
} Prevention
- Normalize all leg InstrumentIds to the same venue before building spreads
- Verify venue/exchange mappings when parsing leg contracts
- Keep multi-venue instruments out of single combo instruments
When it happens
Trigger: Calling create_spread_instrument_id with legs from different venues, e.g. mixing '.OPRA' option legs with another venue's instruments, or leg InstrumentIds parsed with inconsistent/incorrect venue suffixes.
Common situations: Combining option legs from different data sources, misconfigured venue mappings during parsing, or spreading across venues in multi-venue setups.
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
- ratio cannot be zero
- Invalid spread symbol format for component: {component}
- Failed to connect after {max_attempts} attempts
- Unknown IB security type: {value}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e4c66a7f5b0f42ce.
Report an issue: GitHub.