QuantConnect/Lean · error · AssertionError
{method_call} expected {expected}, but received {count}
Error message
{method_call} expected {expected}, but received {count} What it means
Count-check helper assert_history_count that verifies a history slice contains exactly the expected number of elements. It computes count as len(list) for a list result or len(index) otherwise, then compares to expected. The assertion fires when the number of bars/rows returned for a given access method differs from the expected count.
Source
Thrown at Algorithm.Python/PandasDataFrameHistoryAlgorithm.py:145
self.assert_history_count(f"df.loc[{ticker}]", df.loc[ticker], expected)
self.assert_history_count(f"df.xs({ticker})", df.xs(ticker), expected)
self.assert_history_count(f"df.at[(ticker,), '{column}']", list(df.at[(ticker,), column]), expected)
self.assert_history_count(f"df2.loc[{ticker}]", df2.loc[ticker], len(df2.columns))
self.assert_history_count(f"df3[{ticker}]", df3[ticker], expected)
self.assert_history_count(f"df3.get({ticker})", df3.get(ticker), expected)
except Exception as e:
symbols = set(df.index.get_level_values(level='symbol'))
raise AssertionError(f"{symbols}, {symbol.id}, {symbol}, {ticker}. {e}")
def assert_history_count(self, method_call, trade_bar_history, expected):
if isinstance(trade_bar_history, list):
count = len(trade_bar_history)
else:
count = len(trade_bar_history.index)
if count != expected:
raise AssertionError(f"{method_call} expected {expected}, but received {count}")
class QuandlFuture(PythonQuandl):
'''Custom quandl data type for setting customized value column name. Value column is used for the primary trading calculations and charting.'''
def __init__(self):
self.value_column_name = "Settle"
View on GitHub (pinned to d2c3659f87)
Solutions
- Compare the actual data rows for that symbol against the expected window; fill-forward or data gaps are the usual cause.
- Recompute 'expected' dynamically from the actual date range and resolution rather than hard-coding it.
- Confirm the start/end dates and trading-day calendar match what the expectation assumed.
- If data is legitimately partial, relax the assertion to a range or skip it.
Example fix
# before
def assert_history_count(self, method_call, trade_bar_history, expected):
if isinstance(trade_bar_history, list):
count = len(trade_bar_history)
else:
count = len(trade_bar_history.index)
if count != expected:
raise AssertionError(f"{method_call} expected {expected}, but received {count}")
# after (allow the count to be derived, and tolerate fill-forward variance)
def assert_history_count(self, method_call, trade_bar_history, expected, tolerance=0):
count = len(trade_bar_history) if isinstance(trade_bar_history, list) else len(trade_bar_history.index)
if abs(count - expected) > tolerance:
raise AssertionError(f"{method_call} expected {expected} (+/-{tolerance}), but received {count}") Defensive patterns
Strategy: validation
Validate before calling
# Compute expected from the actual range/resolution instead of hard-coding
trading_days = self.trading_calendar.get_trading_days(self.start_date, self.end_date)
expected = len(trading_days)
count = len(trade_bar_history) if isinstance(trade_bar_history, list) else len(trade_bar_history.index)
if count != expected:
self.debug(f"{method_call}: got {count}, expected {expected} (trading days)") Type guard
def count_matches(history, expected, tolerance=0):
"""True when the history element count is within tolerance of expected."""
count = len(history) if isinstance(history, list) else len(history.index)
return abs(count - expected) <= tolerance Prevention
- Derive 'expected' from the date range and resolution rather than a hard-coded constant.
- Account for fill-forward and trading-day calendar differences.
- Allow a small tolerance for data gaps instead of an exact equality.
When it happens
Trigger: For a given access style (e.g. df.loc[str(symbol.id)]), the returned series/list has a count != expected. This happens when the history request returned fewer or more bars than anticipated — e.g. data missing for some dates, fill-forward changing row count, a different resolution producing a different bar count, or a date range that does not span the expected number of trading days.
Common situations: The expected count assumed a specific number of trading days but the data has gaps. Fill-forward (dataNormalization/fill-data-forward) added or removed rows. The backtest date range changed. A data source delivered partial data. The resolution requested (daily/hour/minute) yields a different count than the hard-coded expectation.
Related errors
- History call failed: {e}
- Unexpected columns in SPY tick history
- Empty history data frame for {symbol}
- Could not unstack df. Columns: {', '.join(df.columns)} | {co
- {symbols}, {symbol.id}, {symbol}, {ticker}. {e}
AI-assisted analysis of QuantConnect/Lean@d2c3659f87 (2026-08-13).
Data as JSON: /api/errors/ff6d7a3ca1969ba7.
Report an issue: GitHub.