{"record":{"id":"dcd6d36fd315edc5","repo":"nautechsystems/nautilus_trader","slug":"contract-details-not-found-for-leg-after-loadin","errorCode":null,"errorMessage":"Contract details not found for leg {} after loading","messagePattern":"Contract details not found for leg (.+?) after loading","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/interactive_brokers/src/providers/instruments.rs","lineNumber":2439,"sourceCode":"                    self.price_magnifiers\n                        .insert(leg_instrument_id, leg_details.price_magnifier);\n\n                    leg_instrument_id\n                };\n\n            // Determine ratio (positive for BUY, negative for SELL)\n            let ratio = IbAction::from_str(combo_leg.action.as_str())\n                .context(\"Invalid combo leg action\")?\n                .signed_multiplier()\n                * combo_leg.ratio;\n\n            // Get the contract details for this leg (should be cached now)\n            let leg_details_clone = self\n                .contract_details\n                .get(&leg_instrument_id)\n                .map(|entry| entry.value().clone())\n                .ok_or_else(|| {\n                    anyhow::anyhow!(\n                        \"Contract details not found for leg {} after loading\",\n                        leg_instrument_id\n                    )\n                })?;\n\n            leg_contract_details.push((leg_details_clone, ratio));\n            leg_tuples.push((leg_instrument_id, ratio));\n        }\n\n        if leg_tuples.is_empty() {\n            anyhow::bail!(\"No valid legs loaded for BAG contract\");\n        }\n\n        // Create spread instrument ID from leg tuples\n        let spread_instrument_id = create_spread_instrument_id(&leg_tuples)\n            .context(\"Failed to create spread instrument ID from leg tuples\")?;\n\n        // Fetch BAG contract details (for storing the mapping)","sourceCodeStart":2421,"sourceCodeEnd":2457,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/interactive_brokers/src/providers/instruments.rs#L2421-L2457","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nlet bag = self.fetch_bag_contract(&spread).await?;\n// after\nfor leg in spread.legs() {\n    self.ensure_contract_details_loaded(leg).await?;\n}\nlet bag = self.fetch_bag_contract(&spread).await?;","handlingStrategy":"validation","validationCode":"if !provider.contract_details.contains_key(&leg_id) {\n    provider.load_instrument(leg_id).await?;\n    anyhow::ensure!(provider.contract_details.contains_key(&leg_id), \"leg {leg_id} failed to load\");\n}","typeGuard":"fn leg_cached(provider: &IbInstrumentsProvider, id: &InstrumentId) -> bool {\n    provider.contract_details.contains_key(id)\n}","tryCatchPattern":"match provider.get_instrument(instrument_id).await {\n    Ok(i) => i,\n    Err(e) if e.to_string().contains(\"not found for leg\") => {\n        eprintln!(\"leg cache miss: {e}\");\n        Default::default()\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["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"],"tags":["rust","interactive-brokers","cache-miss","spread"],"backgroundTag":"entity-not-found","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}