Home › Python

TypeError: unhashable type: 'list' — how to fix

Traceback (most recent call last):
  File "app.py", line 3, in <module>
    seen = {[1, 2], [3, 4]}
TypeError: unhashable type: 'list'

Quick fix: Convert the list to a tuple before using it as a key or set member: d[tuple(key)] = value, set(map(tuple, rows)). For dicts use frozenset(d.items()) or json.dumps(d, sort_keys=True). In pandas, convert list columns first: df['col'] = df['col'].apply(tuple).

What it means

Dictionary keys and set members must be hashable: their hash must never change. Lists, dicts and sets are mutable, so Python refuses to hash them. The same error appears as unhashable type: 'dict', unhashable type: 'set', unhashable type: 'numpy.ndarray' or unhashable type: 'Series'.

Typical triggers:

d = {}
d[[1, 2]] = "x"           # list as dict key
s = {[1, 2]}              # list inside a set
set([[1, 2], [1, 2]])     # deduplicating a list of lists
[1, 2] in {"a": 1}        # membership test against a dict/set

Cause 1: a list used as a dict key or set member

Use a tuple. Tuples are hashable as long as everything inside them is hashable.

d[tuple(key)] = value

rows = [[1, 2], [1, 2], [3, 4]]
unique = set(map(tuple, rows))            # {(1, 2), (3, 4)}
unique_lists = [list(t) for t in unique]

To deduplicate while keeping order:

unique = list(dict.fromkeys(map(tuple, rows)))

Cause 2: a dict used as a key or deduplicated

For a flat dict, frozenset(d.items()) is hashable. For nested dicts, serialize to a canonical string:

import json
records = [{"a": 1}, {"a": 1}, {"b": 2}]
seen, out = set(), []
for r in records:
    k = json.dumps(r, sort_keys=True)
    if k not in seen:
        seen.add(k)
        out.append(r)

Cause 3: a set inside a set

Use frozenset:

groups = {frozenset({1, 2}), frozenset({3})}

Cause 4: pandas columns containing lists

df.drop_duplicates(), df.groupby('col'), value_counts() and set(df['col']) all hash values. If a column holds lists (common after json_normalize or str.split), convert them:

df["tags"] = df["tags"].apply(tuple)
df = df.drop_duplicates()

Or only deduplicate on hashable columns: df.drop_duplicates(subset=["id", "name"]).

Passing a list where pandas expects a single label can also trigger it, e.g. df.groupby(df[["a", "b"]]) — use df.groupby(["a", "b"]).

Cause 5: lru_cache / functools.cache with list arguments

@functools.lru_cache hashes the arguments. Pass a tuple instead of a list, or convert inside a wrapper:

from functools import lru_cache

@lru_cache
def total(values: tuple) -> int:
    return sum(values)

total(tuple(my_list))

Cause 6: custom classes with __eq__ but no __hash__

Defining __eq__ sets __hash__ to None, so instances raise unhashable type: 'MyClass'. Add a __hash__ based on immutable fields, or use @dataclass(frozen=True), which generates one:

from dataclasses import dataclass

@dataclass(frozen=True)
class Point:
    x: int
    y: int

{Point(1, 2)}   # works

Last updated 2026-11-05.