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

  1. Compare the actual data rows for that symbol against the expected window; fill-forward or data gaps are the usual cause.
  2. Recompute 'expected' dynamically from the actual date range and resolution rather than hard-coding it.
  3. Confirm the start/end dates and trading-day calendar match what the expectation assumed.
  4. 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

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


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