QuantConnect/Lean · error · AssertionError
{symbols}, {symbol.id}, {symbol}, {ticker}. {e}
Error message
{symbols}, {symbol.id}, {symbol}, {ticker}. {e} What it means
Catch-all in assert_history_index: the helper performs a series of indexing access styles (df.loc, df.xs, df.at, df2, df3) inside a try block to validate that Lean-created dataframes are indexable by ticker, Symbol, and SID string forms. If any of those access styles raises, the except wraps the original exception with the symbol set, the Symbol id/object, the ticker, and the original error for diagnosis.
Source
Thrown at Algorithm.Python/PandasDataFrameHistoryAlgorithm.py:136
self.assert_history_count(f"df.xs(str({symbol}))", df.xs(str(symbol)), expected)
self.assert_history_count(f"df.at[(str({symbol}),), '{column}']", list(df.at[(str(symbol),), column]), expected)
self.assert_history_count(f"df2.loc[str({symbol})]", df2.loc[str(symbol)], len(df2.columns))
self.assert_history_count(f"df3[str({symbol})]", df3[str(symbol)], expected)
self.assert_history_count(f"df3.get(str({symbol}))", df3.get(str(symbol)), expected)
# str : Symbol.VALUE
if len(ticker) == 0:
return
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
- Read the original error ({e}) in the wrapped message — it identifies which access style and which key form failed.
- Inspect the dataframe index labels (df.index) to confirm which key form (ticker, str(Symbol.ID), or Symbol) is actually present.
- If the PandasMapper cannot map the ticker to a SID, ensure SymbolCache has the symbol registered (e.g. it was added via AddEquity/AddData) before indexing.
- For non-unique index errors, deduplicate or use a more specific key (include the time level).
Example fix
# before
except Exception as e:
symbols = set(df.index.get_level_values(level='symbol'))
raise AssertionError(f"{symbols}, {symbol.id}, {symbol}, {ticker}. {e}")
# after (also record the index key forms actually present, to localize the failure)
except Exception as e:
symbols = set(df.index.get_level_values(level='symbol'))
sample_keys = list(df.index.get_level_values(0)[:5])
raise AssertionError(
f"History indexing failed: symbols={symbols}, "
f"symbol={symbol}, ticker={ticker}, err={e}, sample_keys={sample_keys}") Defensive patterns
Strategy: try-catch
Validate before calling
# Confirm the key form is present before the multi-style indexing
labels = set(map(str, df.index.get_level_values(0)))
if str(symbol.id) not in labels and ticker not in labels:
self.debug(f"Neither SID {symbol.id} nor ticker {ticker} in index {sorted(labels)}")
return Type guard
def key_resolvable(df, symbol, ticker):
"""True when the index contains the symbol's SID string or ticker form."""
labels = set(map(str, df.index.get_level_values(0)))
return str(symbol.id) in labels or ticker in labels Try / catch
try:
# the series of df.loc / df.xs / df.at access styles
...
except KeyError as e:
# Indexing key not found — report the index forms available rather than re-raising opaquely
labels = sorted(set(map(str, df.index.get_level_values(0))))
self.debug(f"Key not found for {ticker}/{symbol.id}; index has {labels}: {e}") Prevention
- Ensure the symbol was added (AddEquity/AddData) so SymbolCache can map ticker to SID.
- Index by str(symbol.id) or the Symbol object you obtained from add_*, not a freehand ticker.
- Check index labels before trying multiple access styles.
When it happens
Trigger: Any of the df.loc[ticker], df.xs(ticker), df.at[(ticker,), column], df2.loc[ticker], df3[ticker], or df3.get(ticker) calls inside the try raises (e.g. KeyError because the key form is not in the index, ValueError from a non-unique index, or a TypeError from wrong key shape). The wrapper re-raises with full context. This commonly fires when the PandasMapper key remapping (ticker<->SID) cannot resolve a key form.
Common situations: The dataframe index does not contain the expected key form (e.g. str(Symbol.ID) vs the Symbol object vs the ticker), often after a change to how PandasData builds the multi-index or after a pandas version bump that changed indexing semantics. Custom data whose Symbol/ticker does not match the index labels. A duplicate/non-unique index key causing xs to fail.
Related errors
- No key found for either mapped or original key. Mapped Key:
- 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
AI-assisted analysis of QuantConnect/Lean@d2c3659f87 (2026-08-13).
Data as JSON: /api/errors/0970f1ef6ce98b3b.
Report an issue: GitHub.