Skip to content

How to resolve TypeError when using lists as dictionary keys in Python

Problem

When I tried to use a list as a dictionary key in Python, I got this error:

>>> coords = {[1, 2]: "value"}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

I wanted to store coordinate pairs as dictionary keys for a game board I was building. The error made no sense to me at first—why can’t I use a list as a key when tuples work fine?

What happened?

I was building a simple chess game and needed to track which piece was at each position. My first attempt looked like this:

chess_game.py
# My initial approach - using lists as keys
board = {
[0, 0]: "white_rook",
[0, 1]: "white_knight",
[0, 2]: "white_bishop"
}

When I ran this code, Python immediately threw the TypeError: unhashable type: 'list' error.

I thought maybe I was doing something wrong with the syntax, so I tried adding keys one at a time:

board = {}
position = [0, 0]
board[position] = "white_rook" # Same error

Still the same error. Then I remembered seeing tuples used as dictionary keys in some code examples, so I tried that:

chess_game_fixed.py
# Using tuples instead
board = {
(0, 0): "white_rook",
(0, 1): "white_knight",
(0, 2): "white_bishop"
}
# Access works perfectly
piece = board[(0, 1)] # Returns "white_knight"

This worked! But I didn’t understand why tuples work when lists don’t. Aren’t they both just sequences?

The reason

I think the key reason for this error comes down to how Python dictionaries work internally.

Dictionaries use hash tables for fast lookups. When you add a key-value pair, Python:

  1. Calculates a hash value from the key
  2. Stores the value at that hash location
  3. Uses the hash to quickly find the value later

For this to work, the key’s hash value must never change. If the hash changes, Python won’t be able to find the value anymore.

Here’s the crucial difference:

  • Lists are mutable - you can modify them after creation
  • Tuples are immutable - once created, they cannot change
# Lists can change
my_list = [1, 2]
my_list[0] = 5 # This works
my_list.append(3) # This also works
# Tuples cannot change
my_tuple = (1, 2)
my_tuple[0] = 5 # TypeError: 'tuple' object does not support item assignment

If Python allowed lists as dictionary keys and you modified a list that was being used as a key, its hash would change. Then the dictionary wouldn’t be able to find that key anymore—it would be looking in the wrong hash bucket.

Python prevents this entire problem by making lists unhashable. Tuples don’t have this problem because they can’t be modified, so their hash value stays the same forever.

What I learned about hashability

Through researching this error, I learned that an object is hashable in Python if:

  1. It has a __hash__() method that returns an integer
  2. It has an __eq__() method for comparison
  3. The hash value never changes during the object’s lifetime
  4. Objects that compare equal have the same hash value

I wrote a simple function to check if an object is hashable:

def is_hashable(obj):
try:
hash(obj)
return True
except TypeError:
return False
print(is_hashable((1, 2, 3))) # True
print(is_hashable([1, 2, 3])) # False
print(is_hashable({1, 2, 3})) # False (sets are mutable)
print(is_hashable("hello")) # True (strings are immutable)

This helped me understand what can and cannot be used as dictionary keys.

Common pitfalls I discovered

While working through this, I found two other ways to trigger the same error:

First pitfall: Using tuples that contain mutable elements

# This looks like a tuple, but it contains a list
key = (1, 2, [3, 4])
board = {key: "value"}
# TypeError: unhashable type: 'list'
# Even though the outer structure is a tuple,
# the list inside makes the whole thing unhashable

Second pitfall: Forgetting that nested structures must also be immutable

# This works - all elements are immutable
good_key = (1, 2, (3, 4))
board = {good_key: "value"}
# This doesn't work - contains a list
bad_key = (1, 2, [3, 4])
board = {bad_key: "value"} # TypeError

The rule is: a tuple is only hashable if ALL its elements are hashable.

Practical examples where I use tuple keys

Now that I understand this, I use tuple keys in several situations:

1. Coordinate systems

# Grid or board positions
grid_values = {
(0, 0): "start",
(5, 5): "end",
(2, 3): "obstacle"
}
# 3D coordinates
space = {
(10, 20, 30): "point_a",
(40, 50, 60): "point_b"
}

2. Composite keys

# Student grades by (student_id, semester)
grades = {
(101, "Fall 2024"): {"math": 95, "english": 88},
(101, "Spring 2025"): {"math": 92, "english": 91}
}
# Cache keys combining multiple parameters
cache = {}
def expensive_operation(x, y, mode):
key = (x, y, mode)
if key not in cache:
cache[key] = compute(x, y, mode)
return cache[key]

3. State representation

# Game state as (position, direction)
states = {
((0, 0), "north"): "standing",
((0, 0), "east"): "turning"
}

Why not use strings instead?

I initially thought about just converting my coordinates to strings like “0,0” instead of using tuples. But I found that tuples are better because:

  1. Type safety - integers stay as integers, not strings
  2. No parsing needed - direct access without splitting strings
  3. Faster - no string operations required
  4. Less error-prone - can’t have malformed strings like “0, 2” vs “0,2”
# String approach (what I considered)
string_coords = {"0,0": "value"}
piece = string_coords["0,0"] # Works
piece = string_coords["0, 0"] # KeyError! Extra space breaks it
# Tuple approach (what I use)
tuple_coords = {(0, 0): "value"}
piece = tuple_coords[(0, 0)] # Always works

Summary

In this post, I showed how I resolved the TypeError: unhashable type: 'list' error by switching from lists to tuples when using dictionary keys. The key point is that dictionary keys must be hashable (immutable), so tuples work but lists don’t.

I also learned that:

  • All elements within a tuple must be immutable for the tuple to be hashable
  • Tuples are ideal for composite keys like coordinates and multi-dimensional data
  • Tuples are better than string concatenation for composite keys due to type safety and performance

The error that confused me at first now makes complete sense—it’s Python protecting the integrity of dictionary lookups by ensuring key hashes can never change.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments