nautechsystems/nautilus_trader · error · anyhow::Error
Leg instrument {} not found in contract details after loadin
Error message
Leg instrument {} not found in contract details after loading What it means
fetch_spread_instrument looks up each combo leg's ContractDetails in the provider's contract_details cache by leg InstrumentId. This error means a required leg was not present in the cache after the provider attempted to load it, so the spread cannot be assembled.
Source
Thrown at crates/adapters/interactive_brokers/src/providers/instruments.rs:1304
);
// Load the individual leg instrument
self.fetch_contract_details(
client,
*leg_instrument_id,
force_instrument_update,
filters.clone(),
)
.await
.with_context(|| format!("Failed to load leg instrument: {}", leg_instrument_id))?;
// Get the contract details for this leg
let leg_details = self
.contract_details
.get(leg_instrument_id)
.map(|entry| entry.value().clone())
.ok_or_else(|| {
anyhow::anyhow!(
"Leg instrument {} not found in contract details after loading",
leg_instrument_id
)
})?;
leg_contract_details.push((leg_details, *ratio));
}
// Create the spread instrument
let timestamp = nautilus_core::time::get_atomic_clock_realtime().get_time_ns();
let leg_details_refs: Vec<(&ibapi::contracts::ContractDetails, i32)> =
leg_contract_details.iter().map(|(d, r)| (d, *r)).collect();
let bag_contract = self.create_bag_contract_from_legs(
&leg_contract_details,
Some(spread_instrument_id),
None,
)?;View on GitHub (pinned to 18893faf8b)
Solutions
- Load each leg instrument individually (load_ids_async per leg) and confirm the load succeeds before fetching the spread
- Verify the leg symbol, venue (exchange), and currency exactly match a tradable IB contract
- Check that the leg load path actually inserts into contract_details (look for early returns on empty IB results)
- Retry after the async load completes — the error can occur if the spread is fetched before leg loads finish
Example fix
// before
self.fetch_spread_instrument(instrument, leg_ids).await?;
// after
for leg in leg_ids {
self.load_ids_async(&[leg.clone()], None).await?;
}
self.fetch_spread_instrument(instrument, leg_ids).await?; Defensive patterns
Strategy: validation
Validate before calling
if provider.contract_details.get(&leg_id).is_none() {
provider.load_ids_async(&[leg_id.clone()], None).await?;
} Type guard
fn is_leg_cached(provider: &IbInstrumentsProvider, id: &InstrumentId) -> bool {
provider.contract_details.get(id).is_some()
} Try / catch
match fetch_spread_instrument(...).await {
Ok(i) => Ok(i),
Err(e) if e.to_string().contains("not found in contract details") =>
Err(SpreadError::LegMissing(e.to_string())),
Err(e) => Err(e.into()),
} Prevention
- Verify leg symbol/venue/currency resolve to a real IB contract before spread fetch
- Await all leg loads to completion before fetching the spread
- Log the set of cached leg ids when a spread fetch fails to spot missing legs
When it happens
Trigger: Calling resolve_contract_for_instrument_async / load_with_return_async / load_ids_async for a spread whose leg instrument_id has no entry in self.contract_details after load — e.g. the leg load request returned no matching contract for that symbol/exchange/currency.
Common situations: Leg symbol misspelled or with wrong venue/currency so IB returns no details; leg never individually subscribed/loaded before the spread fetch; IB API returned an empty contract details list for the leg and the cache write was skipped.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- Contract details not found for leg {} after loading
- Resolved BAG spread {spread_instrument_id} is not cached
- Cannot create BAG contract without leg details
- 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/a71ea990b21e600e.
Report an issue: GitHub.