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
- Confirm the symbol, resolution, and period passed to history() are unchanged.
- Inspect the underlying data files for the symbol/date range; added or removed bars change the count.
- Trace the history provider pipeline for fillForward/exchange-hours filtering changes that add or drop bars.
- 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
- Treat expected history counts as baselines that must be updated alongside data/engine changes.
- Log the actual count on mismatch before failing, to speed diagnosis.
- Pin symbol, resolution, and period in helper methods to avoid drift.
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
- Unexpected multi symbol dividend count: {len(multi_symbol_re
- Unexpected continuous future mapping event count: {len(conti
- Unexpected continuous future mapping event count: {len(conti
- Unexpected dividend count: {len(dividend)}
- Unexpected distribution: {distribution}
AI-assisted analysis of QuantConnect/Lean@d2c3659f87 (2026-08-13).
Data as JSON: /api/errors/55c9daaee196c03e.
Report an issue: GitHub.