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

  1. Pass a single hashable label: pd.col('a') or pd.col(0).
  2. For multiple columns, compose Expressions: pd.col('a') + pd.col('b').
  3. 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

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


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)