TypeError: unhashable type: 'list' — decoded
Exception: TypeErrorCategory: runtimeRaised at: the moment the value is hashed
What this message means
Dictionaries and sets make a promise about their keys and members: once stored, the thing can be found again instantly. To keep that promise they convert each key to a hash — a fingerprint. Lists refuse to be fingerprinted, because a list can change at any moment and a changed list would have a different fingerprint. So the moment a list reaches a place that hashes its values, Python raises this TypeError.
Read the message as: "the value you gave me here is a list, and this spot only accepts hashable values — things that cannot change."
Traceback (most recent call last):
File "main.py", line 1, in <module>
counts = {[1, 2]: "pair"}
^^^^^^
TypeError: unhashable type: 'list'
A real example
seen = set()
point = [3, 4] # a coordinate you want to remember
seen.add(point) # TypeError: unhashable type: 'list'
The fix is one character of thinking: a coordinate never changes once created, so say so with parentheses instead of brackets. A tuple is the immutable sibling of a list, and immutable means hashable:
point = (3, 4) # tuple — cannot change, can be hashed
seen.add(point) # works
grid = {(3, 4): "start", (0, 0): "corner"} # tuple keys are the standard
print(grid[(3, 4)]) # start
Where this error appears
- Dict keys.
{[1, 2]: "x"}— lists as keys. Keys must stay findable, so they must be hashable. - Set members.
seen.add([1, 2])— same rule; sets are dicts with only keys. - After converting accidentally.
set([[1, 2], [3, 4]])— a list of lists; convert the inner lists to tuples first. - DataFrame indexes and groupby keys in pandas — the same hashing rule surfaces there as this same message.
- A loop variable that is a list.
d[key] = valuewherekeycame from splitting or slicing — the key is a list without you noticing.
# The standard conversion when you must go list -> hashable
points = [[3, 4], [3, 4], [5, 1]]
unique = {tuple(p) for p in points} # {(3, 4), (5, 1)}
counts = {}
for p in points:
counts[tuple(p)] = counts.get(tuple(p), 0) + 1
What is hashable, exactly
The rule is simple: immutable built-ins are hashable; mutable containers are not. Numbers, strings, tuples (of hashable things), frozenset, bytes — all hashable. Lists, dicts, sets, bytearray — all unhashable. A tuple is the bridge: it is the container you reach for whenever you need a list-shaped value in a key-shaped place.
One subtlety: a tuple *containing* a list is still unhashable — ([1, 2], 3) has a mutable thing inside, so its fingerprint cannot be trusted. Hash the whole way down: ((1, 2), 3).
Related messages worth knowing
- TypeError: the parent guide — the five famous wordings decoded together.
- KeyError — the dict-key story this page is the other half of.
- TypeError: list indices must be integers — the mirror mistake — putting a string where a position belongs.
Fix it interactively
These free problems practice the dict-key and set-member rules — repair them in the browser:
Practice more Python bugs →🇮🇳 Hindi में समझें
Dict और set अपनी keys/members को hash करके रखते हैं — यानी एक fingerprint बनाकर, ताकि दोबारा ढूंढना instant रहे। इसलिए key या set-member change नहीं होना चाहिए। List कभी भी बदल सकती है — इसलिए list key या set-member बन ही नहीं सकती और unhashable type: list मिलता है। Fix: list की जगह tuple लो — (3, 4)। Tuple immutable है, इसलिए hashable भी। Rule याद रखो: immutable (number, string, tuple, frozenset) = hashable; mutable (list, dict, set) = unhashable। Coordinates, pairs और composite keys के लिए tuple hi Python का standard तरीका है।