Python KeyError (tested)
KeyError means you asked a dictionary for a key it doesn't have, using d[key] or an equivalent. Unlike dict.get(), which returns None quietly, square-bracket access raises immediately. The traceback's one line (KeyError: 'name') tells you which key was missing but not why — that part depends on which of the patterns below you hit.
1. Reading the error
KeyError: 'c' means the string after KeyError: is the exact key that was looked up and not found — not a message, just the key itself, shown with repr(). That is different from most exceptions, which carry a sentence. If the key is a number or tuple, you'll see that form instead, e.g. KeyError: 1 or KeyError: ('a', 'b').
2. Seven reproduced cases
| Code | Exact error (Python 3.13.5) |
|---|---|
d = {"a": 1, "b": 2}; d["c"] | KeyError: 'c' |
d.pop("z") (no default) | KeyError: 'z' |
l = ["a","b"]; l[5] | IndexError: list index out of range (not KeyError — see section 6) |
os.environ["PATH_X"] (unset var) | KeyError: 'PATH_X' |
count["x"] += 1 (key never initialized) | KeyError: 'x' |
del d["nope"] | KeyError: 'nope' |
row["age"] (CSV/JSON row missing a field) | KeyError: 'age' |
3. Cause 1: the key really is absent
The plain case: a typo, a key that only exists sometimes, or data that changed shape.
>>> d = {"a": 1, "b": 2}
>>> d["c"]
KeyError: 'c'
Fix: use d.get("c") (returns None) or d.get("c", default) if a missing key is expected. Use d["c"] only when the key's presence is a program invariant you want enforced loudly.
4. Cause 2: pop() and del without a default
dict.pop(key) and del d[key] both raise KeyError if the key isn't there — they don't silently no-op.
>>> d.pop("z")
KeyError: 'z'
>>> del d["nope"]
KeyError: 'nope'
Fix for pop: give a default, d.pop("z", None). For del, check first with if key in d:, since del has no built-in default form.
5. Cause 3: incrementing a counter that doesn't exist yet
A very common one in hand-rolled counting code:
>>> count = {}
>>> count["x"] += 1
KeyError: 'x'
count["x"] += 1 is sugar for count["x"] = count["x"] + 1, and the read on the right-hand side fails first. Fix: use collections.Counter (auto-initializes to 0), or collections.defaultdict(int), or count["x"] = count.get("x", 0) + 1.
6. Cause 4: confusing it with IndexError
These get mixed up in conversation but are different exceptions for different containers:
>>> l = ["a", "b"]
>>> l[5]
IndexError: list index out of range
KeyError is for mappings (dict and dict-like objects) looked up by key. IndexError is for sequences (list, tuple, str) looked up by numeric position. os.environ and parsed JSON objects are dict-like, so a missing field there is KeyError, not IndexError.
7. Cause 5: environment variables and parsed rows
os.environ behaves exactly like a dict, so an unset environment variable raises the same way:
>>> import os
>>> os.environ["PATH_X"]
KeyError: 'PATH_X'
Fix: os.environ.get("PATH_X", "default"), or os.environ["PATH_X"] wrapped in a startup check that fails with a clear message if required config is missing. The same applies to rows from csv.DictReader or json.load(): a field that's present in most rows but missing in one will raise KeyError only on that row, which is why it often surfaces late, deep into a batch job.
8. Fix checklist
- Use
d.get(key, default)whenever a missing key is a normal, expected case. - Use
d[key](and let it raise) when a missing key means something is actually broken and you want to know immediately. - For counters/accumulators, reach for
collections.Counterorcollections.defaultdictinstead of hand-checking keys. - For batch processing of rows (CSV/JSON/API responses), validate the expected keys once up front, or wrap the per-row access in
try/except KeyErrorso one malformed row doesn't kill the whole run. - To catch both a missing key and a wrong-type value in one place, catch
(KeyError, TypeError)together.
If the value you looked up turned out to be None instead of missing entirely, see AttributeError: 'NoneType' object has no attribute — a different dict pitfall (.get() succeeding with a None value) that produces a different error on the next line.
Frequently asked questions
What does KeyError: 'x' actually mean?
It means code tried to look up the key 'x' in a dictionary (or dict-like object such as os.environ) using square brackets, and that key does not exist. The value shown after KeyError: is the exact key, printed with repr(), not an error message.
What is the difference between KeyError and IndexError?
KeyError is raised by mappings (dict and dict-like objects) when a key lookup fails. IndexError is raised by sequences (list, tuple, str) when a numeric position is out of range. They are unrelated exception types for different container kinds.
Why did count["x"] += 1 raise KeyError on a dict that's empty?
Because += reads the current value before writing the new one, equivalent to count['x'] = count['x'] + 1. The read fails with KeyError if 'x' was never set. Use collections.Counter or defaultdict(int) to avoid this.
How do I avoid KeyError when reading CSV or JSON data?
Use dict.get('field', default) instead of dict['field'] for optional fields, or validate the expected keys once before processing. For batch jobs, wrap per-row key access in try/except KeyError so one bad row doesn't stop the whole run.
Does dict.pop() raise KeyError if the key is missing?
Yes, unless you give it a default: d.pop('key') raises KeyError on a missing key, while d.pop('key', None) returns None instead. del d['key'] always raises on a missing key; it has no default form.
Written with AI assistance. Measured on 2026-10-03 with Python 3.13.5 on Linux using plain python3 one-liners. Every traceback below is copy-pasted output, not paraphrased. PlainHeaders is our extension; Python is free.