{"record":{"id":"5352659ec557f658","repo":"nautechsystems/nautilus_trader","slug":"python-on-option-chain-failed-e","errorCode":null,"errorMessage":"Python on_option_chain failed: {e}","messagePattern":"Python on_option_chain failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/common/src/python/actor.rs","lineNumber":1163,"sourceCode":"\n    fn on_instrument_status(&mut self, data: &InstrumentStatus) -> anyhow::Result<()> {\n        self.dispatch_on_instrument_status(*data)\n            .map_err(|e| anyhow::anyhow!(\"Python on_instrument_status failed: {e}\"))\n    }\n\n    fn on_instrument_close(&mut self, update: &InstrumentClose) -> anyhow::Result<()> {\n        self.dispatch_on_instrument_close(*update)\n            .map_err(|e| anyhow::anyhow!(\"Python on_instrument_close failed: {e}\"))\n    }\n\n    fn on_option_greeks(&mut self, greeks: &OptionGreeks) -> anyhow::Result<()> {\n        self.dispatch_on_option_greeks(*greeks)\n            .map_err(|e| anyhow::anyhow!(\"Python on_option_greeks failed: {e}\"))\n    }\n\n    fn on_option_chain(&mut self, slice: &OptionChainSlice) -> anyhow::Result<()> {\n        self.dispatch_on_option_chain(slice.clone())\n            .map_err(|e| anyhow::anyhow!(\"Python on_option_chain failed: {e}\"))\n    }\n\n    #[cfg(feature = \"defi\")]\n    fn on_block(&mut self, block: &Block) -> anyhow::Result<()> {\n        self.dispatch_on_block(block.clone())\n            .map_err(|e| anyhow::anyhow!(\"Python on_block failed: {e}\"))\n    }\n\n    #[cfg(feature = \"defi\")]\n    fn on_pool(&mut self, pool: &Pool) -> anyhow::Result<()> {\n        self.dispatch_on_pool(pool.clone())\n            .map_err(|e| anyhow::anyhow!(\"Python on_pool failed: {e}\"))\n    }\n\n    #[cfg(feature = \"defi\")]\n    fn on_pool_swap(&mut self, swap: &PoolSwap) -> anyhow::Result<()> {\n        self.dispatch_on_pool_swap(swap.clone())\n            .map_err(|e| anyhow::anyhow!(\"Python on_pool_swap failed: {e}\"))","sourceCodeStart":1145,"sourceCodeEnd":1181,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/common/src/python/actor.rs#L1145-L1181","documentation":"This error wraps any Python exception raised inside the actor's `on_option_chain` callback when an `OptionChainSlice` is dispatched to the Python subclass. Note the slice is cloned before conversion (`slice.clone().into_py_any`), so the error typically arises either in that conversion or inside the user's Python handler. The Rust `PyDataActor` converts the `PyErr` to an anyhow error with this message.","triggerScenarios":"Any exception raised by the user's `on_option_chain(self, slice)` override — e.g. indexing into an empty chain slice, calling methods on individual chain entries that don't exist, or a failure converting OptionChainSlice into a Python object.","commonSituations":"Options strategies processing chain snapshots at expiry when the chain is empty; handlers assuming every slice has strikes and quotes; version changes to OptionChainSlice structure.","solutions":["Read the appended Python traceback after 'Python on_option_chain failed:' to find the raising line.","Handle empty slices (`if not slice.strikes: return`) before processing.","Iterate the chain defensively rather than assuming fixed indices.","Verify OptionChainSlice fields against the installed nautilus_trader version."],"exampleFix":"// before\ndef on_option_chain(self, slice):\n    best = slice.strikes[0]\n\n// after\ndef on_option_chain(self, slice):\n    if not slice.strikes:\n        return\n    best = slice.strikes[0]","handlingStrategy":"validation","validationCode":"strikes = getattr(slice, \"strikes\", []) or []\nif not strikes:\n    return  # empty chain snapshot","typeGuard":"def is_nonempty_chain(chain_slice):\n    return bool(getattr(chain_slice, \"strikes\", None))","tryCatchPattern":"def on_option_chain(self, slice):\n    try:\n        self._process_chain(slice)\n    except Exception as e:\n        self.log.error(f\"on_option_chain failed: {e}\", exc_info=True)","preventionTips":["Handle empty chain slices (common near expiry) before indexing","Iterate chains rather than assuming fixed indices","Check OptionChainSlice structure against your installed version","Feed synthetic chain slices in unit tests"],"tags":["python","rust-bridge","callback-exception","actor"],"backgroundTag":"python-callback-failed","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"}