{"record":{"id":"8c1fac1e11e17818","repo":"nautechsystems/nautilus_trader","slug":"cannot-create-bag-contract-without-leg-details","errorCode":null,"errorMessage":"Cannot create BAG contract without leg details","messagePattern":"Cannot create BAG contract without leg details","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/interactive_brokers/src/providers/instruments.rs","lineNumber":1196,"sourceCode":"            }\n        }\n\n        Ok(loaded_ids)\n    }\n\n    fn create_bag_contract_from_legs(\n        &self,\n        leg_contract_details: &[(ibapi::contracts::ContractDetails, i32)],\n        instrument_id: Option<InstrumentId>,\n        bag_contract: Option<&Contract>,\n    ) -> anyhow::Result<Contract> {\n        if let Some(bag_contract) = bag_contract {\n            return Ok(bag_contract.clone());\n        }\n\n        let (first_details, _) = leg_contract_details\n            .first()\n            .ok_or_else(|| anyhow::anyhow!(\"Cannot create BAG contract without leg details\"))?;\n\n        let combo_legs = leg_contract_details\n            .iter()\n            .map(|(details, ratio)| ibapi::contracts::ComboLeg {\n                contract_id: details.contract.contract_id,\n                ratio: ratio.abs(),\n                action: if *ratio > 0 {\n                    LegAction::Buy\n                } else {\n                    LegAction::Sell\n                },\n                exchange: details.contract.exchange.to_string(),\n                open_close: ComboLegOpenClose::Same,\n                short_sale_slot: 0,\n                designated_location: String::new(),\n                exempt_code: -1,\n            })\n            .collect();","sourceCodeStart":1178,"sourceCodeEnd":1214,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/interactive_brokers/src/providers/instruments.rs#L1178-L1214","documentation":"This error is thrown when creating an IB BAG (combo/spread) contract but the leg_contract_details slice passed in is empty. A BAG contract requires at least one ComboLeg built from ContractDetails, so an empty legs list is an invariant violation. The library throws it defensively in create_bag_contract_from_legs before dereferencing the first leg.","triggerScenarios":"fetch_spread_instrument resolves a spread whose component legs have no cached contract details, or the spread definition has an empty legs list; the earlier per-leg lookup stage silently produced zero entries.","commonSituations":"Requesting a spread instrument before its legs were individually resolved/cached; a corrupted or partially loaded instrument definition whose legs vector is empty; a race where leg loads were skipped due to an earlier error.","solutions":["Ensure each leg instrument's contract details are loaded into contract_details before calling fetch_spread_instrument","Check that the spread instrument definition actually contains legs (non-empty ratios/leg list)","Log leg_instrument_ids prior to fetching to confirm the legs collection is populated","Verify the earlier leg-loading call returned Ok and was not swallowed upstream"],"exampleFix":"// before\nlet legs: Vec<(ContractDetails, i64)> = Vec::new();\nlet bag = create_bag_contract_from_legs(&legs)?;\n// after\nassert!(!legs.is_empty(), \"spread must define at least one leg\");\nlet bag = create_bag_contract_from_legs(&legs)?;","handlingStrategy":"validation","validationCode":"if leg_contract_details.is_empty() {\n    return Err(anyhow::anyhow!(\"refusing to create BAG: no leg details\"));\n}","typeGuard":"fn has_legs(legs: &[(ContractDetails, i64)]) -> bool { !legs.is_empty() }","tryCatchPattern":"match provider.fetch_spread_instrument(...) {\n    Ok(inst) => inst,\n    Err(e) if e.to_string().contains(\"without leg details\") => {\n        eprintln!(\"spread legs missing: {e}\");\n        return None;\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always load individual legs before requesting a spread instrument","Validate spread definitions contain at least one leg at config load time","Handle leg-load errors instead of swallowing them so failures propagate early"],"tags":["rust","interactive-brokers","spread","empty-collection"],"backgroundTag":"empty-required-field","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}