QuantConnect/Lean · error · RegressionTestException

Expected {expected_chain_count} futures in chain on {date},

Error message

Expected {expected_chain_count} futures in chain on {date}, but got {actual_chain_count}

What it means

Per-date chain-count comparison. For each date in the history result, the test contrasts len(future_chain_provider.get_future_contract_list(future, date)) against the row count in the historical DataFrame for that date. A mismatch aborts, proving the history result and the live chain provider agree.

Source

Thrown at Algorithm.Python/FutureUniverseHistoryRegressionAlgorithm.py:43

        future = self.add_future(Futures.Indices.SP_500_E_MINI).symbol

        historical_futures_data_df = self.history(FutureUniverse, future, 3, flatten=True)

        # Level 0 of the multi-index is the date, we expect 3 dates, 3 future chains
        if historical_futures_data_df.index.levshape[0] != 3:
            raise RegressionTestException(f"Expected 3 futures chains from history request, "
                                          f"but got {historical_futures_data_df.index.levshape[1]}")

        for date in historical_futures_data_df.index.levels[0]:
            expected_chain = list(self.future_chain_provider.get_future_contract_list(future, date))
            expected_chain_count = len(expected_chain)

            actual_chain = historical_futures_data_df.loc[date]
            actual_chain_count = len(actual_chain)

            if expected_chain_count != actual_chain_count:
                raise RegressionTestException(f"Expected {expected_chain_count} futures in chain on {date}, "
                                              f"but got {actual_chain_count}")

            for i, symbol in enumerate(actual_chain.index):
                expected_symbol = expected_chain[i]
                if symbol != expected_symbol:
                    raise RegressionTestException(f"Expected symbol {expected_symbol} at index "
                                                  f" {i} on {date}, but got {symbol}")

View on GitHub (pinned to d2c3659f87)

Solutions

  1. Compare expected_chain and actual_chain contents for the failing date to identify added/missing contracts.
  2. Confirm both calls use the same date resolution (UTC vs exchange tz).
  3. Re-pull or re-run the data generator for the affected date.
  4. If the chain provider is now intentionally richer, update the regression expectations.
Defensive patterns

Strategy: validation

Validate before calling

# Pre-compare counts per date
for date in df.index.levels[0]:
    expected = len(list(self.future_chain_provider.get_future_contract_list(future, date)))
    actual = len(df.loc[date])
    if expected != actual:
        self.debug(f"Chain mismatch on {date}: expected={expected} actual={actual}")

Type guard

def chain_counts_match(provider, future, df) -> bool:
    return all(
        len(list(provider.get_future_contract_list(future, d))) == len(df.loc[d])
        for d in df.index.levels[0]
    )

Prevention

When it happens

Trigger: FutureUniverse history snapshot taken at a different time-of-day than the chain provider query; the chain provider returning a different contract set after a data refresh; stale or partial chain files for the queried date.

Common situations: Data provider inconsistency between history and chain endpoints; timezone differences making 'date' resolve to adjacent days; data refreshes that add/remove contracts; engine changes to FutureUniverse filtering.

Related errors


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