TypeError: unhashable type: 'set' (tested fix)
TypeError: unhashable type: 'set' means a set was used as a set member or a dict key. Sets are mutable, so they cannot be hashed. We reproduced each case on Python 3.13 and tested the fix, frozenset.
1. Cause: a set inside a set, or a set as a dict key
groups = [{"a", "b"}, {"b", "a"}, {"c"}]
for label, action in [("set of sets", lambda: set(groups)),
("dict key", lambda: {groups[0]: 1}),
("set.add", lambda: set().add(groups[0]))]:
try:
action()
except TypeError as e:
print(f"{label:12} TypeError: {e}")
Output:
set of sets TypeError: unhashable type: 'set'
dict key TypeError: unhashable type: 'set'
set.add TypeError: unhashable type: 'set'
Set members and dict keys must be hashable, and a set is mutable, so it has no hash. Typical triggers: deduplicating a list of sets (tags, permissions, graph edges), or counting pairs with a set as the dict key.
2. Fix: use frozenset
# Fix: frozenset is the immutable, hashable set
groups = [{"a", "b"}, {"b", "a"}, {"c"}]
unique = {frozenset(g) for g in groups}
print(len(unique), sorted(sorted(g) for g in unique))
pair_count = {frozenset({"alice", "bob"}): 3}
print(pair_count[frozenset({"bob", "alice"})]) # order doesn't matter
Output:
2 [['a', 'b'], ['c']]
3
frozenset is the immutable version of set. It is hashable, and two frozensets with the same members are equal whatever the order they were built in, which makes it a good key for unordered pairs. You cannot add() to it; build a new one instead.
3. Nested braces: {{...}} is a set of a set
# Easy to miss: {x} is a set literal, so {{"a"}} is a set containing a set
try:
nested = {{"a", "b"}}
except TypeError as e:
print("TypeError:", e)
print({frozenset({"a", "b"})})
Output:
TypeError: unhashable type: 'set'
{frozenset({'b', 'a'})}
{x} is a set literal, so double braces try to put a set inside a set. This often comes from f-string or template habits, where {{ means a literal brace. Note that the display order of set members varies between runs (string hashing is randomised).
Related: unhashable type: 'list' · unhashable type: 'dict' · unhashable type: 'slice'.
Frequently asked questions
Why is a set unhashable?
Sets are mutable, so their hash could change. Python only allows hashable values as set members and dict keys.
How do I make a set of sets?
Convert the inner sets to frozenset: {frozenset(s) for s in list_of_sets}.
Can I use a set as a dictionary key?
Not directly; use frozenset(s) as the key. Two frozensets with the same members compare and hash equal.
Written with AI assistance. Measured on 2026-10-23 with Python 3.13.5 on Debian: a set inside a set, a set as a dict key, set.add(set), the frozenset fix, and a nested {{...}} literal. Every block was run verbatim and its output pasted unedited. PlainHeaders is our extension; Python is free.