QuantConnect/Lean · error · AssertionError

{} expected {}, but received {}

Error message

{} expected {}, but received {}

What it means

assert_history_count in HistoryAlgorithm compares the number of bars returned by a History() request against an expected count. A mismatch means the history provider returned a different number of data points than the test was baselined against, indicating a data, resolution, or history-provider regression.

Source

Thrown at Algorithm.Python/HistoryAlgorithm.py:138

        custom_data_spyvalues = all_custom_data.loc["IBM"]["value"]
        self.assert_history_count("all_custom_data.loc[\"IBM\"][\"value\"]", custom_data_spyvalues, 250)
        for value in custom_data_spyvalues:
            # do something with 'IBM.custom_data_equity' value data
            pass

    def on_data(self, data):
        '''on_data event is the primary entry point for your algorithm. Each new data point will be pumped in here.

        Arguments:
            data: Slice object keyed by symbol containing the stock data
        '''
        if not self.portfolio.invested:
            self.set_holdings("SPY", 1)

    def assert_history_count(self, method_call, trade_bar_history, expected):
        count = len(trade_bar_history.index)
        if count != expected:
            raise AssertionError("{} expected {}, but received {}".format(method_call, expected, count))


class CustomDataEquity(PythonData):
    def get_source(self, config, date, is_live):
        zip_file_name = LeanData.generate_zip_file_name(config.Symbol, date, config.Resolution, config.TickType)
        source = Globals.data_folder + "/equity/usa/daily/" + zip_file_name
        return SubscriptionDataSource(source)

    def reader(self, config, line, date, is_live):
        if line == None:
            return None

        custom_data = CustomDataEquity()
        custom_data.symbol = config.symbol

        csv = line.split(",")
        custom_data.time = datetime.strptime(csv[0], '%Y%m%d %H:%M')
        custom_data.end_time = custom_data.time + timedelta(days=1)

View on GitHub (pinned to d2c3659f87)

Solutions

  1. Confirm the symbol, resolution, and period passed to history() are unchanged.
  2. Inspect the underlying data files for the symbol/date range; added or removed bars change the count.
  3. Trace the history provider pipeline for fillForward/exchange-hours filtering changes that add or drop bars.
  4. If the new count is correct, update the expected value passed to assert_history_count and document why.

Example fix

# before
self.assert_history_count('History<TradeBar>(SPY, 10, daily)', history, 10)
# after: expected recalculated after a data correction
self.assert_history_count('History<TradeBar>(SPY, 10, daily)', history, 9)
Defensive patterns

Strategy: validation

Validate before calling

# wrap history calls with a count guard helper
def safe_history(algo, *args, expected=None, **kwargs):
    h = algo.history(*args, **kwargs)
    if expected is not None and len(h.index) != expected:
        algo.debug(f"history count {len(h.index)} != expected {expected}")
    return h

Prevention

When it happens

Trigger: len(trade_bar_history.index) != expected after a self.history(...) call that the test invokes via assert_history_count(method_call, history, expected).

Common situations: History provider (SubscriptionDataReaderHistoryProvider / SynchronizingHistoryProvider) change; data file changes/additions/removals in the data folder; resolution or fillForward behavior change; the requested period or symbol changed.

Related errors


AI-assisted analysis of QuantConnect/Lean@d2c3659f87 (2026-08-13). Data as JSON: /api/errors/55c9daaee196c03e. Report an issue: GitHub.