nautechsystems/nautilus_trader · error · anyhow::Error
Contract details not found for leg {} after loading
Error message
Contract details not found for leg {} after loading What it means
fetch_bag_contract reads each combo leg's ContractDetails from the provider cache, expecting it to have been cached during an earlier load. This error means the leg is still absent from contract_details after the load phase, so the BAG contract cannot be built.
Source
Thrown at crates/adapters/interactive_brokers/src/providers/instruments.rs:2439
self.price_magnifiers
.insert(leg_instrument_id, leg_details.price_magnifier);
leg_instrument_id
};
// Determine ratio (positive for BUY, negative for SELL)
let ratio = IbAction::from_str(combo_leg.action.as_str())
.context("Invalid combo leg action")?
.signed_multiplier()
* combo_leg.ratio;
// Get the contract details for this leg (should be cached now)
let leg_details_clone = self
.contract_details
.get(&leg_instrument_id)
.map(|entry| entry.value().clone())
.ok_or_else(|| {
anyhow::anyhow!(
"Contract details not found for leg {} after loading",
leg_instrument_id
)
})?;
leg_contract_details.push((leg_details_clone, ratio));
leg_tuples.push((leg_instrument_id, ratio));
}
if leg_tuples.is_empty() {
anyhow::bail!("No valid legs loaded for BAG contract");
}
// Create spread instrument ID from leg tuples
let spread_instrument_id = create_spread_instrument_id(&leg_tuples)
.context("Failed to create spread instrument ID from leg tuples")?;
// Fetch BAG contract details (for storing the mapping)View on GitHub (pinned to 18893faf8b)
Solutions
- Load each leg's contract details individually and verify success before requesting the BAG contract
- Validate leg definitions (symbol, exchange, currency) resolve to real IB contracts
- Serialize spread fetches so legs are guaranteed cached before combination
- Inspect for cache eviction or non-insertion paths when IB returns empty contract details
Example fix
// before
let bag = self.fetch_bag_contract(&spread).await?;
// after
for leg in spread.legs() {
self.ensure_contract_details_loaded(leg).await?;
}
let bag = self.fetch_bag_contract(&spread).await?; Defensive patterns
Strategy: validation
Validate before calling
if !provider.contract_details.contains_key(&leg_id) {
provider.load_instrument(leg_id).await?;
anyhow::ensure!(provider.contract_details.contains_key(&leg_id), "leg {leg_id} failed to load");
} Type guard
fn leg_cached(provider: &IbInstrumentsProvider, id: &InstrumentId) -> bool {
provider.contract_details.contains_key(id)
} Try / catch
match provider.get_instrument(instrument_id).await {
Ok(i) => i,
Err(e) if e.to_string().contains("not found for leg") => {
eprintln!("leg cache miss: {e}");
Default::default()
}
Err(e) => return Err(e.into()),
} Prevention
- Ensure the leg load stage runs to completion and inserts cache entries before BAG fetch
- Confirm each leg maps to a real IB contract (symbol/exchange/currency) in isolation
- Avoid fetching spreads with stale definitions after provider restarts
When it happens
Trigger: get_instrument resolves a spread whose leg instrument_id was never inserted into the contract_details cache — the preceding leg load found no matching IB contract, or cache insertion was skipped for that leg.
Common situations: Leg symbol/venue/currency doesn't match a real IB contract so the load yields nothing; spread fetched concurrently before leg loads complete; provider restarted with an empty cache but stale spread definitions.
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
- Leg instrument {} not found in contract details after loadin
- 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/dcd6d36fd315edc5.
Report an issue: GitHub.