pandas-dev/pandas · error · KeyError
Column not found
Error message
Column not found: {key} What it means
Raised by SelectionMixin.__getitem__ when a scalar (non-list-like) key is passed to a groupby/rolling/expanding/resample selection and key not in self.obj is true. This is the single-column selector path: grouped['col']. The check uses __contains__ on the DataFrame so it matches column labels only, not index values.
Solutions
- Verify the key with `key in df.columns` before selection.
- Fix the spelling/case to match df.columns exactly.
- Strip whitespace from headers at load time: pd.read_csv(...).rename(columns=str.strip).
- If selecting by index position, use .iloc/.nth on the groupby object instead.
Example fix
// before
g = df.groupby('id')['valu']
// after
assert 'value' in df.columns, df.columns.tolist()
g = df.groupby('id')['value'] Defensive patterns
Strategy: validation
Validate before calling
if key not in df.columns:
raise KeyError(f'{key!r} not in {df.columns.tolist()}')
grouped = df.groupby('id')[key] Type guard
def is_known_column(df, key) -> bool:
return key in df.columns Prevention
- Use df.columns membership checks before scalar selection on groupby/window objects.
- Avoid hardcoding column names scattered through code; centralize them.
When it happens
Trigger: df.groupby('a')['misspelled']; window objects such as df.rolling(2)['b'] where 'b' was dropped; selecting on a Series groupby (where there are no columns); using a numeric label on a string-columned DataFrame.
Common situations: Typos and case errors in column names; selecting after rename/drop without updating downstream code; passing an index label instead of a column label; whitespace from CSV headers.
Related errors
- Columns not found
- Cannot mask with non-boolean array containing NA / NaN…
- Cannot perform with non-ordered Categorical
- Cannot slice with Ellipsis
- Cannot slice with
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/3f956cf17f8df33d.
Report an issue: GitHub.
Appendix: source
Thrown at pandas/core/base.py:224
if len(self.exclusions) > 0:
return self.obj._drop_axis(self.exclusions, axis=1)
else:
return self.obj
def __getitem__(self, key):
if self._selection is not None:
raise IndexError(f"Column(s) {self._selection} already selected")
if isinstance(key, (list, tuple, ABCSeries, ABCIndex, np.ndarray)):
if len(self.obj.columns.intersection(key)) != len(set(key)):
bad_keys = list(set(key).difference(self.obj.columns))
raise KeyError(f"Columns not found: {str(bad_keys)[1:-1]}")
return self._gotitem(list(key), ndim=2)
else:
if key not in self.obj:
raise KeyError(f"Column not found: {key}")
ndim = self.obj[key].ndim
return self._gotitem(key, ndim=ndim)
def _gotitem(self, key, ndim: int, subset=None):
"""
sub-classes to define
return a sliced object
Parameters
----------
key : str / list of selections
ndim : {1, 2}
requested ndim of result
subset : object, default None
subset to act on
"""
raise AbstractMethodError(self)
View on GitHub (pinned to 3b7651241d)