pandas TypeError: unhashable type: 'dict' (groupby, nunique, merge)

TypeError: unhashable type: 'dict' in pandas means a column holds Python dicts (usually from nested JSON) and you called something that hashes cells: groupby, nunique, unique or merge. Flatten it with pd.json_normalize or group on a json.dumps(..., sort_keys=True) key. Tested on pandas 2.3.3 and 3.1.0.

1. Which pandas methods fail on dict cells

import pandas as pd
rows = [{"id": 1, "meta": {"src": "web", "v": 2}},
        {"id": 2, "meta": {"src": "app", "v": 1}},
        {"id": 3, "meta": {"src": "web", "v": 2}}]
df = pd.DataFrame(rows)
for name, f in [("drop_duplicates", lambda: len(df.drop_duplicates(subset="meta"))),
                ("duplicated", lambda: df["meta"].duplicated().tolist()),
                ("value_counts", lambda: df["meta"].value_counts().tolist()),
                ("groupby", lambda: df.groupby("meta").size()),
                ("nunique", lambda: df["meta"].nunique()),
                ("unique", lambda: df["meta"].unique()),
                ("set_index+loc", lambda: df.set_index("meta").loc[{"src": "web", "v": 2}]),
                ("merge", lambda: df.merge(df, on="meta"))]:
    try:
        print(f"{name}: {f()}")
    except TypeError as e:
        print(f"{name}: TypeError: {e}")

Output, identical on pandas 2.3.3 and 3.1.0:

drop_duplicates: 2
duplicated: [False, False, True]
value_counts: [2, 1]
groupby: TypeError: unhashable type: 'dict'
nunique: TypeError: unhashable type: 'dict'
unique: TypeError: unhashable type: 'dict'
set_index+loc: TypeError: Passing a dict as an indexer is not supported. Use a list instead.
merge: TypeError: unhashable type: 'dict'

groupby, nunique, unique and merge on a column of dicts raise unhashable type: 'dict'. drop_duplicates, duplicated and value_counts did not raise on either version: they found the duplicate dict and dropped it. (With list cells, drop_duplicates does raise; see the list version.) Dict cells nearly always come from loading nested JSON with pd.DataFrame(records) or read_json.

2. Fix: a JSON key column, or flatten with json_normalize

import json
import pandas as pd
rows = [{"id": 1, "meta": {"src": "web", "v": 2}},
        {"id": 2, "meta": {"v": 1, "src": "app"}},
        {"id": 3, "meta": {"v": 2, "src": "web"}}]
df = pd.DataFrame(rows)
# Option A: a hashable key column (sort_keys so key order doesn't matter)
df["meta_key"] = df["meta"].apply(lambda d: json.dumps(d, sort_keys=True))
print(df["meta_key"].nunique())
print(df.groupby("meta_key")["id"].apply(list))
# Option B: flatten the dicts into real columns
flat = pd.json_normalize(rows)
print(flat)
print(flat.groupby(["meta.src", "meta.v"]).size())

Output, identical on pandas 2.3.3 and 3.1.0:

2
meta_key
{"src": "app", "v": 1}       [2]
{"src": "web", "v": 2}    [1, 3]
Name: id, dtype: object
   id meta.src  meta.v
0   1      web       2
1   2      app       1
2   3      web       2
meta.src  meta.v
app       1         1
web       2         2
dtype: int64

json.dumps(d, sort_keys=True) gives each dict a string key that is hashable, and sort_keys makes {"v": 2, "src": "web"} and {"src": "web", "v": 2} the same key (rows 1 and 3 group together above). If you need the values themselves, pd.json_normalize turns the nested keys into real columns (meta.src, meta.v) that group, merge and filter normally.

3. Passing a dict where pandas expects labels

import pandas as pd
df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
mapping = {"a": "A"}
try:
    df[mapping]
except TypeError as e:
    print("df[dict]: TypeError:", e)
print(df.rename(columns=mapping).columns.tolist())

Output, identical on pandas 2.3.3 and 3.1.0:

df[dict]: TypeError: Passing a dict as an indexer is not supported. Use a list instead.
['A', 'b']

Indexing with a dict, df[mapping] or .loc[dict], gives a different message: Passing a dict as an indexer is not supported. If the dict was meant to rename columns, pass it to rename(columns=...); if you wanted to select columns, use df[list(mapping)]. For the plain-Python version of this error (dict as a dict key or set member), see TypeError: unhashable type: 'dict'.

Related: unhashable type: 'Series' · unhashable type: 'numpy.ndarray' · merge KeyError.

Frequently asked questions

How do I group by a column of dicts in pandas?

Group on a string key built with df['col'].apply(lambda d: json.dumps(d, sort_keys=True)), or flatten the dicts into columns with pd.json_normalize and group on those.

Why does drop_duplicates work on dict cells but groupby fails?

In our test drop_duplicates, duplicated and value_counts handled dict cells, while groupby, nunique, unique and merge raised, on both pandas 2.3.3 and 3.1.0.

What does 'Passing a dict as an indexer is not supported' mean?

You used a dict inside df[...] or .loc[...]. Use rename(columns=mapping) to rename, or df[list(mapping)] to select those columns.

Written with AI assistance. Measured on 2026-10-23 in the python:3-alpine Docker image (Python 3.14.7) with pandas 2.3.3 and pandas 3.1.0. Outputs pasted unedited. PlainTables is our extension; Python and pandas are free.