{"record":{"id":"0d048910c24bb4ab","repo":"QuantConnect/Lean","slug":"expected-expected-chain-count-options-in-chain-o","errorCode":null,"errorMessage":"Expected {expected_chain_count} options in chain on {date}, but got {actual_chain_count}","messagePattern":"Expected (.+?) options in chain on (.+?), but got (.+?)","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"Algorithm.Python/OptionUniverseHistoryRegressionAlgorithm.py","lineNumber":42,"sourceCode":"        self.set_end_date(2015, 12, 25)\n\n        option = self.add_option(\"GOOG\").symbol\n\n        historical_options_data_df = self.history(option, 3, flatten=True)\n\n        # Level 0 of the multi-index is the date, we expect 3 dates, 3 option chains\n        if historical_options_data_df.index.levshape[0] != 3:\n            raise AssertionError(f\"Expected 3 option chains from history request, but got {historical_options_data_df.index.levshape[1]}\")\n\n        for date in historical_options_data_df.index.levels[0]:\n            expected_chain = list(self.option_chain_provider.get_option_contract_list(option, date))\n            expected_chain_count = len(expected_chain)\n\n            actual_chain = historical_options_data_df.loc[date]\n            actual_chain_count = len(actual_chain)\n\n            if expected_chain_count != actual_chain_count:\n                raise AssertionError(f\"Expected {expected_chain_count} options in chain on {date}, but got {actual_chain_count}\")\n\n            for i, symbol in enumerate(actual_chain.index):\n                expected_symbol = expected_chain[i]\n                if symbol != expected_symbol:\n                    raise AssertionError(f\"Expected symbol {expected_symbol} at index {i} on {date}, but got {symbol}\")\n","sourceCodeStart":24,"sourceCodeEnd":48,"githubUrl":"https://github.com/QuantConnect/Lean/blob/d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892/Algorithm.Python/OptionUniverseHistoryRegressionAlgorithm.py#L24-L48","documentation":"For each date level in the history DataFrame, the regression compares the number of contracts returned by history (actual_chain_count) against the count from option_chain_provider.get_option_contract_list(option, date) (expected_chain_count). A mismatch means the OptionUniverse history provider and the option chain provider disagree on the universe for that date — a consistency bug in Lean's option universe generation/caching.","triggerScenarios":"len(historical_options_data_df.loc[date]) != len(option_chain_provider.get_option_contract_list(option, date)) for some date in the history window. Triggered by a change in how the history provider vs the chain provider enumerate/filter the option universe, or by data version skew between the two code paths.","commonSituations":"Refactoring option universe generation so history and chain provider use different filtering; a caching stale-data issue; a data package where the two providers read different files for the same date.","solutions":["Diff the OptionUniverse history provider and the option_chain_provider code paths to ensure they enumerate the same contracts.","Re-generate or re-download the option universe data so both providers read identical rows.","Log both lists for the failing date to see which contracts differ.","Verify no implicit filter (e.g. strikes/expiry window) is applied in one path but not the other."],"exampleFix":"# diagnostic: log the divergence before asserting\nmissing = set(map(str, expected_chain)) - set(map(str, actual_chain.index))\nextra = set(map(str, actual_chain.index)) - set(map(str, expected_chain))\nself.log(f'date={date} missing={missing} extra={extra}')\nif expected_chain_count != actual_chain_count:\n    raise AssertionError(...)","handlingStrategy":"validation","validationCode":"# Compare counts and log divergence before asserting\nexpected_chain = list(self.option_chain_provider.get_option_contract_list(option, date))\nactual_chain = self.history(option, 3, flatten=True).loc[date]\nif len(expected_chain) != len(actual_chain):\n    self.log(f'date={date} provider={len(expected_chain)} history={len(actual_chain)}')\n    raise AssertionError('chain count mismatch')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the history provider and chain provider enumeration logic consistent in Lean.","Re-generate option universe data so both providers read identical rows.","Log both lists for the failing date to localize the divergence.","Ensure no implicit filter is applied in one path only."],"tags":["options","history","option-chain-provider","regression-test","quantconnect","consistency"],"backgroundTag":null,"analyzedSha":"d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892","analyzedAt":"2026-08-13T13:52:21.013Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}