pandas-dev/pandas · error · TypeError
Expected Hashable, got
Error message
Expected Hashable, got: {type(col_name)} What it means
Raised by the pandas.col() factory when col_name is not an instance of Hashable. pd.col(name) builds a deferred column reference for use in assign/loc/query; the column label must be hashable so it can be looked up in df.columns later. Lists, dicts, ndarrays, and other unhashable types are rejected up front with a TypeError naming the actual type received.
Solutions
- Pass a single hashable label: pd.col('a') or pd.col(0).
- For multiple columns, compose Expressions: pd.col('a') + pd.col('b').
- If the name is dynamic, validate isinstance(name, Hashable) before calling pd.col.
Example fix
// before
expr = pd.col(['speed', 'weight'])
// after
expr = pd.col('speed') + pd.col('weight') Defensive patterns
Strategy: type-guard
Validate before calling
from collections.abc import Hashable
if not isinstance(name, Hashable):
raise TypeError(f'pd.col expects a Hashable, got {type(name)}')
expr = pd.col(name) Type guard
def is_hashable(x) -> bool:
try:
hash(x)
except TypeError:
return False
return True Prevention
- Pass a single column label, not a list, to pd.col.
- Validate Hashable before constructing an Expression dynamically.
When it happens
Trigger: pd.col(['a','b']) (list of names); pd.col({'a':1}); pd.col(np.array([1,2])); pd.col([None]) — all unhashable. Passing a tuple is allowed (tuples are hashable).
Common situations: Confusing pd.col (single-column reference) with selecting multiple columns; passing a parsed JSON list directly; refactoring old lambda df: df[['a','b']] code into pd.col without splitting.
Related errors
- boolean value of an expression is ambiguous
- Expression objects are not copiable
- Expression objects are not iterable
- ExtensionArray.fillna does not support filling with a dict…
- periods must be an integer, got
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/8eb713a7f446d9fb.
Report an issue: GitHub.
Appendix: source
Thrown at pandas/core/col.py:413
--------
You can use `col` in `assign`.
>>> df = pd.DataFrame({"name": ["beluga", "narwhal"], "speed": [100, 110]})
>>> df.assign(name_titlecase=pd.col("name").str.title())
name speed name_titlecase
0 beluga 100 Beluga
1 narwhal 110 Narwhal
You can also use it for filtering.
>>> df.loc[pd.col("speed") > 105]
name speed
1 narwhal 110
"""
if not isinstance(col_name, Hashable):
msg = f"Expected Hashable, got: {type(col_name)}"
raise TypeError(msg)
def func(df: DataFrame) -> Series:
if col_name not in df.columns:
columns_str = str(df.columns.tolist())
max_len = 90
if len(columns_str) > max_len:
columns_str = columns_str[:max_len] + "...]"
msg = (
f"Column '{col_name}' not found in given DataFrame.\n\n"
f"Hint: did you mean one of {columns_str} instead?"
)
raise ValueError(msg)
return df[col_name]
return Expression(func, f"col({col_name!r})")
View on GitHub (pinned to 3b7651241d)