TypeError: unhashable type: 'slice' (tested fix)
TypeError: unhashable type: 'slice' means code like d[0:2] tried to slice a dict. Since Python 3.12 slices are hashable, so the same bug now shows up as KeyError: slice(0, 2, None). We reproduced both on 3.11 and 3.13 and tested the fixes.
1. Cause: slicing a dict
import sys
print(sys.version.split()[0])
d = {"a": 1, "b": 2, "c": 3}
try:
d[0:2] # slicing a dict
except (TypeError, KeyError) as e:
print(f"{type(e).__name__}: {e}")
try:
hash(slice(0, 2))
print("slice is hashable")
except TypeError as e:
print(f"{type(e).__name__}: {e}")
Output on Python 3.11:
3.11.17
TypeError: unhashable type: 'slice'
TypeError: unhashable type: 'slice'
Output on Python 3.13:
3.13.5
KeyError: slice(0, 2, None)
slice is hashable
d[0:2] passes a slice(0, 2, None) object to the dict as a key. Dicts have no order-based slicing, so Python hashes the slice to look it up. Up to Python 3.11 slices were unhashable, giving TypeError: unhashable type: 'slice'. Python 3.12 made slice objects hashable, so the same line now raises KeyError: slice(0, 2, None). Same bug, different message after an upgrade.
2. Fix: slice the items, then rebuild the dict
# Fix: slice the keys/items, not the dict
from itertools import islice
d = {"a": 1, "b": 2, "c": 3}
print(dict(list(d.items())[0:2]))
print(dict(islice(d.items(), 2))) # no full list copy
Output (Python 3.13):
{'a': 1, 'b': 2}
{'a': 1, 'b': 2}
Dicts keep insertion order, so "the first two entries" is well defined. itertools.islice avoids copying every item into a list first, which matters for large dicts.
3. A custom __getitem__ that forwards to a dict
# A custom class whose __getitem__ uses the key in a dict
class Cache:
def __init__(self): self.data = {0: "x", 1: "y", 2: "z"}
def __getitem__(self, key): return self.data[key]
c = Cache()
try:
c[0:2]
except (TypeError, KeyError) as e:
print(f"{type(e).__name__}: {e}")
class Fixed(Cache):
def __getitem__(self, key):
if isinstance(key, slice):
return [self.data[i] for i in range(*key.indices(len(self.data)))]
return self.data[key]
print(Fixed()[0:2])
Output on Python 3.11:
TypeError: unhashable type: 'slice'
['x', 'y']
Output on Python 3.13:
KeyError: slice(0, 2, None)
['x', 'y']
Classes that wrap a dict (caches, datasets, config objects) receive the slice in __getitem__ and pass it straight to the dict. Check isinstance(key, slice) and expand it with key.indices(len(...)), which also handles negative and missing bounds.
Related: unhashable type: 'list' · unhashable type: 'dict' · slice indices must be integers or None.
Frequently asked questions
What causes unhashable type: 'slice'?
Slicing a dict (or a class that forwards the key to a dict), as in d[0:2]. On Python 3.11 and earlier, slices could not be hashed.
Why do I get KeyError: slice(0, 2, None)?
Same bug on Python 3.12+: slices became hashable, so the dict looks the slice up as a key and does not find it.
How do I get the first n items of a dict?
dict(itertools.islice(d.items(), n)), or dict(list(d.items())[:n]).
Written with AI assistance. Measured on 2026-10-23 with Python 3.13.5 on Debian and 3.11.17 / 3.8.20 in python:alpine containers: d[0:2] on a dict, hash(slice), two fixes, and a dict-backed __getitem__. Every block was run verbatim and its output pasted unedited. PlainHeaders is our extension; Python is free.