QuantConnect/Lean · error · KeyError

No key found for either mapped or original key. Mapped Key:

Error message

No key found for either mapped or original key. Mapped Key: {mKey}; Original Key: {oKey}

What it means

PandasMapper wraps pandas indexing functions (DataFrame.__getitem__, loc/xs/at, Index.get_loc) so Lean-created dataframes can be indexed by ticker or Symbol as well as by SID. wrap_keyerror_function first tries the mapped (SID-converted) key, then the original key; if both raise KeyError, it raises this consolidated KeyError listing both the mapped key and the original key attempted. It means neither the ticker/Symbol nor its SID form exists in the dataframe index.

Source

Thrown at Common/PandasMapper.py:93

            newkwargs = kwargs

            if len(args) > 1:
                newargs = mapper(args)
            if len(kwargs) > 0:
                newkwargs = mapper(kwargs)

            return f(*newargs, **newkwargs)
        except KeyError as e:
            pass

        # Execute original
        # Allows for df, Series, etc indexing for keys like 'SPY' if they exist
        try:
            return f(*args, **kwargs)
        except KeyError as e:
            mKey = [str(arg) for arg in newargs if isinstance(arg, str) or isinstance(arg, Symbol)]
            oKey = [str(arg) for arg in args if isinstance(arg, str) or isinstance(arg, Symbol)]
            raise KeyError(f"No key found for either mapped or original key. Mapped Key: {mKey}; Original Key: {oKey}")

    wrapped_function.__name__ = f.__name__
    return wrapped_function

def wrap_bool_function(f):
    '''Wraps function f with wrapped_function, used for functions that reply true/false if key is found.
    wrapped_function attempts with the original args, if its false, it converts the args / kwargs to use
    alternative index keys and then attempts with the mapped args.
    '''
    def wrapped_function(*args, **kwargs):

        # Try the original args; if true just return true
        originalResult = f(*args, **kwargs)
        if originalResult:
            return originalResult

        # Try our mapped args; return this result regardless
        newargs = args

View on GitHub (pinned to d2c3659f87)

Solutions

  1. Confirm the symbol was actually included in the History request (df.index.get_level_values('symbol').unique()) before indexing.
  2. Ensure the security was added (AddEquity/AddData) so SymbolCache can map the ticker to the SID.
  3. Index by the canonical SID string str(symbol.id) or by the Symbol object you got from add_equity, not a freehand ticker.
  4. Guard with `'SPY' in df.index` (the wrapped __contains__ supports ticker/Symbol) before accessing.

Example fix

# before — index with a ticker not present in the history frame
history = self.history([self.spy, self.eur], 30, Resolution.DAILY)
apple = history.loc['AAPL']  # KeyError: No key found ... Mapped Key: ['AAPL']; Original Key: ['AAPL']

# after — verify membership and use the Symbol object you added
history = self.history([self.spy, self.eur], 30, Resolution.DAILY)
if str(self.spy.id) not in history.index.get_level_values('symbol').unique():
    raise ValueError("SPY not in history result")
spy_rows = history.loc[str(self.spy.id)]
Defensive patterns

Strategy: validation

Validate before calling

# Confirm the key form exists in the index before indexing
available = set(map(str, history.index.get_level_values(0)))
key = str(self.spy.id)
if key not in available and 'SPY' not in available:
    raise ValueError(f"SPY not in history index; available: {sorted(available)}")
spy_rows = history.loc[key]

Type guard

def key_in_history(history, symbol, ticker):
    """True when the history index contains the symbol's SID string or ticker."""
    labels = set(map(str, history.index.get_level_values(0)))
    return str(symbol.id) in labels or ticker in labels

Try / catch

try:
    rows = history.loc[str(self.spy.id)]
except KeyError:
    available = sorted(set(map(str, history.index.get_level_values(0))))
    self.debug(f"SPY not in history; index labels: {available}")
    rows = None

Prevention

When it happens

Trigger: You index a Lean history dataframe with a label that is not in the index under any supported form. E.g. df.loc['AAPL'] when the index only contains SPY/EUR rows; df[symbol] for a symbol never added; df.xs(str(symbol.id)) for a SID that was not part of the history request. The mapper tried the SID (via SymbolCache.try_get_symbol) and the raw key, found neither, and raised. This also fires if SymbolCache has no entry for the ticker so the mapped key equals the original and both miss.

Common situations: Indexing a multi-symbol history frame with a symbol/ticker that was not in the request. Using a ticker string before the security was AddEquity'd (SymbolCache empty). A typo in the ticker. Indexing after the dataframe was sliced/filtered so the label is gone. Custom data symbols whose SID string differs from what the caller used.

Related errors


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