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.