KeyError: 'email'

Python · updated 2026-11-02

Raised on a line that reads d['key'] when the dict has no such key. The message is the missing key itself, so KeyError: 'email' means the dict had no 'email'. pandas raises it too when a column name doesn't exist, often because of whitespace or case in a CSV header.

Traceback (most recent call last):
  File "/srv/app/worker.py", line 31, in handle
    send_receipt(payload["customer"]["email"])
                 ~~~~~~~~~~~~~~~~~~~^^^^^^^^^
KeyError: 'email'

Quick fix

Log the dict's keys right before the failing line to see what arrived, then decide: if the key is optional, read it with .get() and handle the missing case; if it is required, raise a clear error that says which input was missing it. Don't wrap the line in a bare except KeyError, which hides the real cause.

  1. Print or log list(d.keys()) (or df.columns for pandas) right before the failing line.
  2. Compare the actual keys with the one you asked for: spelling, case, whitespace, nesting level.
  3. For optional keys use d.get(key) or d.get(key, default) and handle None.
  4. For required keys validate the input once at the boundary (request parsing, job payload) and fail with a clear message.
  5. In pandas, normalize headers once: df.columns = df.columns.str.strip().str.lower().
python
# Optional key: read it safely
email = payload.get("customer", {}).get("email")
if email is None:
    log.warning("no customer email in payload %s", payload.get("id"))
    return

# Required key: fail with a message that names the input
try:
    email = payload["customer"]["email"]
except KeyError as e:
    raise ValueError(f"payload {payload.get('id')} is missing {e}") from None

Why it happens

The data has a different shape than the code expects

An API changed a field name, nests it one level deeper, or omits it when empty. Code written against one sample response breaks on the first response that differs, which is why KeyError often appears only in production.

Typo, case or whitespace in the key

'Email' vs 'email', 'user_id' vs 'userId', or a CSV header that is ' email' with a leading space. The key looks right when you read the code and is still not in the dict.

Reading a key before it was set

A cache or counter dict is read before the first write for that key. collections.defaultdict or d.setdefault() fits this pattern better than plain indexing.

pandas column or index label not found

df['col'] and df.loc[label] raise KeyError for a missing column or row label. After a merge, overlapping columns get _x and _y suffixes, so the original name no longer exists.

Environment variable missing

os.environ['API_KEY'] raises KeyError when the variable isn't set in that environment, typically a new server, a cron job or a container that doesn't load the same .env file.

Other fixes

  • Validate external payloads with a schema (pydantic, dataclasses with a parser) so missing fields fail at the edge with a clear message.
  • Use collections.defaultdict(int) or Counter for counters instead of checking keys by hand.
  • For settings, read os.environ.get('NAME') at startup and refuse to start when a required one is missing.

Same error, other wording

  • KeyError: 0
  • KeyError: "None of [Index(['col'], dtype='object')] are in the [columns]"
  • KeyError: 'API_KEY'

Let your coding agent catch the next one

Runheed records this error in production with the stack trace, the breadcrumbs before it and the agent session that shipped the code, and serves it to Claude Code, Cursor or any MCP client. With it connected, you can ask:

> Find the KeyError exceptions in production, show the line and the payload or request behind the latest one, work out whether the key is missing, misspelled or nested differently, and handle it at the input boundary.

Plans from $29/moSee the setupCancel any time from the billing portal

Related errors

References: Python: Built-in exceptions (KeyError), Python: dict.get and mapping types