KeyError —
The dictionary hash lookup came up empty.
You asked a dictionary for a key that doesn't exist in it. It's the dictionary equivalent of IndexError — same underlying idea, "this position doesn't exist," just for hash-based lookup instead of a sequence position. Watch the lookup fail on LearnBug and see exactly which key was missing.
What is KeyError?
Python raises KeyError when you access my_dict[key] with a key that isn't present in the dictionary. Unlike a list, a dictionary has no concept of "out of range" — it either has the exact key you asked for, or it doesn't, with no partial match or nearby fallback.
Why visualization helps
The traceback names the missing key, but not always why your code assumed it would be there — was the dictionary built from unreliable external data, or is a key genuinely optional? LearnBug shows the dictionary's actual keys at the moment of the lookup, right next to the key you're asking for, so the mismatch is visible immediately.
Three ways a key ends up missing
The key genuinely isn't there
An optional field — like "email" on a user that never provided one — assumed to always exist, when it's actually sometimes absent by design.
Typo or case mismatch in the key
Dictionary keys are matched exactly — "Email" and "email" are different keys, and "email " with a trailing space is different from both.
Counting/grouping into a dict without initializing first
Incrementing counts[word] += 1 on the first time a word appears crashes, because that key hasn't been set to a starting value yet.
user["email"] on a dict without that key
user = {"name": "Alex", "age": 30} — only two keys exist
The dictionary was built with exactly two key-value pairs. There is no "email" key anywhere in it — not empty, not None, simply not present.
user["email"] — Python does a hash lookup for exactly "email"
Python computes a hash of the key "email" and checks if that hash exists in the dictionary's internal hash table. It doesn't — there's no near match, no fuzzy lookup.
The [] lookup raises KeyError immediately, naming the missing key
Square-bracket access on a dictionary always raises if the key is missing — there's no default return value, unlike the .get() method.
Result: KeyError: 'email' ✗
The broken code, and the traceback it produces
user = {"name": "Alex", "age": 30}
print(user["email"])Traceback (most recent call last):
File "user.py", line 2, in <module>
print(user["email"])
~~~~^^^^^^^^^^
KeyError: 'email'Use .get() with a default, or check first
user = {"name": "Alex", "age": 30}
# Fix 1: .get() returns None (or a custom default) instead of raising
email = user.get("email", "no email on file")
print(email)
# Fix 2: check membership before accessing
if "email" in user:
print(user["email"])
else:
print("no email on file")Quick Reference
Frequently asked questions
What's the difference between dict[key] and dict.get(key)?
dict[key] raises KeyError if the key is missing. dict.get(key) returns None instead (or a custom default you pass as a second argument), never raising. Use [] when the key genuinely must exist and its absence is a bug worth knowing about immediately; use .get() when a missing key is a normal, expected case.
What is defaultdict and when should I use it?
collections.defaultdict(int) creates a dictionary where accessing a missing key automatically creates it with a default value (0 for int, an empty list for list, etc.) instead of raising KeyError. It's ideal for counting or grouping patterns — counts[word] += 1 just works even the first time word appears.
Why does the traceback show the key with quotes, like 'email'?
Python's KeyError message includes the actual key value (using repr()), which is genuinely useful — it tells you exactly which key was missing, not just that some key was missing. Compare this to a generic "key not found" message, which wouldn't tell you whether it was a typo, a case mismatch, or a truly absent field.
Does KeyError apply to sets too?
No — sets don't support key-based lookup at all (there's no my_set[x] syntax), so KeyError doesn't apply to them. Removing a missing element from a set with .remove() raises a different error, KeyError as well actually, since set.remove() specifically reuses it — but membership checks with in never raise on either sets or dicts.
Watch the dictionary lookup fail, and see the actual keys
Paste your code into LearnBug and see exactly which key was missing.