{"record":{"id":"243cd6921b328c0f","repo":"nautechsystems/nautilus_trader","slug":"cannot-cache-futures-spread-missing-option-instru-243cd6","errorCode":null,"errorMessage":"Cannot cache futures spread: missing option instrument {put_instrument_id}","messagePattern":"Cannot cache futures spread: missing option instrument (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/common/src/greeks.rs","lineNumber":1061,"sourceCode":"    pub fn cache_futures_spread(\n        &self,\n        call_instrument_id: InstrumentId,\n        put_instrument_id: InstrumentId,\n        futures_instrument_id: InstrumentId,\n    ) -> anyhow::Result<Price> {\n        let cache = self.cache.borrow();\n        let call_instrument = cache.instrument(&call_instrument_id).cloned();\n        let put_instrument = cache.instrument(&put_instrument_id).cloned();\n        let reference_future_instrument = cache.instrument(&futures_instrument_id).cloned();\n        drop(cache);\n\n        let Some(call_instrument) = call_instrument else {\n            anyhow::bail!(\n                \"Cannot cache futures spread: missing option instrument {call_instrument_id}\"\n            );\n        };\n        let Some(put_instrument) = put_instrument else {\n            anyhow::bail!(\n                \"Cannot cache futures spread: missing option instrument {put_instrument_id}\"\n            );\n        };\n        let Some(reference_future_instrument) = reference_future_instrument else {\n            anyhow::bail!(\n                \"Cannot cache futures spread: no reference futures instrument for {futures_instrument_id}\"\n            );\n        };\n\n        if call_instrument.instrument_class() != InstrumentClass::Option\n            || put_instrument.instrument_class() != InstrumentClass::Option\n        {\n            anyhow::bail!(\n                \"Cannot cache futures spread: non-option instruments provided call_instrument_id={call_instrument_id} put_instrument_id={put_instrument_id}\"\n            );\n        }\n\n        if call_instrument.option_kind() != Some(OptionKind::Call)","sourceCodeStart":1043,"sourceCodeEnd":1079,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/common/src/greeks.rs#L1043-L1079","documentation":"Same failure family as the call-side error: `cache_futures_spread` requires the put option instrument of the pair, and it was not found in the cache, so the futures-spread price cannot be computed. The call instrument was found but the put instrument lookup returned None.","triggerScenarios":"Calling `cache_futures_spread(...)` with a `put_instrument_id` absent from the cache — put-leg instrument never loaded, wrong symbol/venue, or only one side of the options pair was subscribed/registered.","commonSituations":"Loading only call options from a chain snapshot; symbol formatting mismatch between the put leg and the cached definitions; adapter that publishes call instruments but not puts for the expiry.","solutions":["Ensure the full option chain (both call and put legs) is loaded into the cache before calling `cache_futures_spread`","Verify the `put_instrument_id` symbol and venue against `cache.instrument_ids()`","Register the missing put instrument definition from the provider data source"],"exampleFix":"// before\ngreeks.cache_futures_spread(&call_id, &put_id, &future_id)?;\n// after\nfor id in [&call_id, &put_id, &future_id] {\n    assert!(cache.instrument(id).is_some(), \"{id} missing from cache\");\n}\ngreeks.cache_futures_spread(&call_id, &put_id, &future_id)?;","handlingStrategy":"validation","validationCode":"fn ensure_pair_cached(cache: &Cache, call: &InstrumentId, put: &InstrumentId) -> Result<(), String> {\n    for id in [call, put] {\n        if cache.instrument(id).is_none() {\n            return Err(format!(\"{id} not in cache\"));\n        }\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"match greeks.cache_futures_spread(&call_id, &put_id, &future_id) {\n    Ok(()) => (),\n    Err(e) if e.to_string().contains(\"missing option instrument\") => {\n        tracing::warn!(\"{e}; ensure put leg is loaded\");\n        return Ok(());\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always load both legs of an options pair together","Verify put symbol formatting matches cached instrument definitions","Assert presence of all three instruments (call, put, future) before spread caching"],"tags":["rust","greeks","cache","missing-instrument"],"backgroundTag":"resource-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"}