QuantConnect/Lean · error · RegressionTestException

Expected symbol {expected_symbol} at index {i} on {date}, b

Error message

Expected symbol {expected_symbol} at index  {i} on {date}, but got {symbol}

What it means

Order-sensitive symbol check inside the same FutureUniverse history loop. After counts match, the test walks actual_chain.index position-by-position and compares each Symbol against expected_chain[i]. The first position where they differ aborts.

Source

Thrown at Algorithm.Python/FutureUniverseHistoryRegressionAlgorithm.py:49

        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. Print expected_chain and list(actual_chain.index) side by side to find the divergent position.
  2. Confirm both sources sort by the same key (typically expiry then strike).
  3. Check Symbol equality semantics — compare .underlying / .id rather than the full object if mapping differs.
  4. If sort order changed intentionally, realign the regression rather than reordering data.
Defensive patterns

Strategy: validation

Validate before calling

# Detect ordering divergence before raising
for date in df.index.levels[0]:
    expected = list(self.future_chain_provider.get_future_contract_list(future, date))
    actual = list(df.loc[date].index)
    for i, (e, a) in enumerate(zip(expected, actual)):
        if e != a:
            self.debug(f"Symbol order differs at {i} on {date}: expected={e} actual={a}")

Type guard

def chains_same_order(provider, future, df) -> bool:
    for d in df.index.levels[0]:
        exp = list(provider.get_future_contract_list(future, d))
        act = list(df.loc[d].index)
        if exp != act:
            return False
    return True

Prevention

When it happens

Trigger: The history result orders contracts differently from future_chain_provider.get_future_contract_list (e.g. by expiry vs by symbol string); a contract added/removed shifting positions; Symbol equality failing due to canonical vs mapped differences.

Common situations: Sort-order changes between engine versions; data refreshes inserting a contract mid-chain; Symbol comparison mismatch when one side is a continuous canonical and the other a mapped contract.

Related errors


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