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

CodeExact 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

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.