pandas-dev/pandas · error · TypeError

Expected Hashable, got: {type(col_name)}

Error message

Expected Hashable, got: {type(col_name)}

What it means

Raised by pandas.col (pandas/core/col.py:413) when the `col_name` argument is not an instance of Hashable. pd.col stores the name for later deferred lookup against a DataFrame, so it must be a hashable label (str, int, tuple of hashables, etc.). Unhashable types like list, dict, or ndarray cannot serve as column keys and are rejected up front.

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 71959b8cb9)

Solutions

  1. Pass a single hashable name: `pd.col('a')` or `pd.col(0)`.
  2. For multiple columns, build separate Expressions: `[pd.col(c) for c in ['a','b']]`.
  3. If you have a tuple column (MultiIndex level), pass the full tuple: `pd.col(('a','b'))`.

Example fix

# before
pd.col(['speed','name'])

# after
[pd.col(c) for c in ['speed','name']]
Defensive patterns

Strategy: validation

Validate before calling

from typing import Hashable

def safe_col(name):
    if not isinstance(name, Hashable):
        raise TypeError(f'col_name must be Hashable, got {type(name).__name__}')
    import pandas as pd
    return pd.col(name)

Type guard

from typing import Hashable

def is_hashable_name(name) -> bool:
    try:
        hash(name)
        return isinstance(name, Hashable)
    except TypeError:
        return False

Try / catch

try:
    expr = pd.col(name)
except TypeError as e:
    if 'Expected Hashable' in str(e):
        name = name[0] if isinstance(name, (list, tuple)) and len(name) == 1 else name
        expr = pd.col(name)
    else:
        raise

Prevention

When it happens

Trigger: `pd.col(['a','b'])` (passing a list), `pd.col({'x':1})`, `pd.col(np.array([1,2]))`, or any mutable/unhashable object. Also `pd.col(df)` where df is a DataFrame.

Common situations: Confusing pd.col (single deferred column) with multi-column selection. Passing a dynamic list computed at runtime without picking a single element.

Related errors


AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07). Data as JSON: /api/errors/8eb713a7f446d9fb. Report an issue: GitHub.