Quick summary
Summarize this blog with AI
KeyError means a mapping lookup requested a key that is absent. Start with the failing key and the actual available keys. Do not catch every exception or replace a required value with zero just to keep a report running. These examples use Python 3.12.14; the DataFrame example is checked with pandas 2.2.3 and 3.0.6.
Inspect the missing key and preserve required-field failures
order = {"order_id": "A1", "amount_cents": 1250}
try:
print(order["amount"])
except KeyError as error:
print("missing:", error.args[0])
print("available:", sorted(order))
print(order["amount_cents"])
Expected output:
missing: amount
available: ['amount_cents', 'order_id']
1250
The fix is the correct schema key, not a broad except: pass. In real logs, list field names only when appropriate; avoid printing confidential record values. If a required field genuinely is missing, reject the input with a clear error and retained provenance. dict.get is a policy choice for optional data, not a universal KeyError repair.
Distinguish absent, None and valid zero
MISSING = object()
for record in [{}, {"discount_cents": None}, {"discount_cents": 0}]:
value = record.get("discount_cents", MISSING)
if value is MISSING:
print("absent")
elif value is None:
print("explicitly unknown")
else:
print("known:", value)
Expected output:
absent
explicitly unknown
known: 0
record.get(key, default) uses the default only when the key is absent. A present None is still returned as None. Avoid record.get(key) or 0 when it would conflate absence, unknown data and other falsy values. If a dictionary can change concurrently, a prior membership check is not an atomic guarantee; design synchronization at the owner of the shared state.
Normalize schema labels only if collisions are rejected
def normalized_keys(record):
result = {}
for key, value in record.items():
if not isinstance(key, str):
raise TypeError("schema keys must be strings")
normalized = key.strip().lower()
if not normalized or normalized in result:
raise ValueError("empty or colliding normalized key")
result[normalized] = value
return result
print(normalized_keys({" Amount_Cents ": 1250}))
try:
normalized_keys({"Amount": 1, " amount ": 2})
except ValueError as error:
print(str(error))
Expected output:
{'amount_cents': 1250}
empty or colliding normalized key
This helper applies a deliberate contract for schema field names. It is not a cleanup rule for arbitrary identifiers, names or case-sensitive business keys. Preserve the raw input separately. Silently overwriting one collision would lose evidence about which field was authoritative.
Check DataFrame columns and index labels separately
import pandas as pd
frame = pd.DataFrame({"Amount ": [10, 20]}, index=[100, 200])
print([repr(column) for column in frame.columns])
try:
frame["Amount"]
except KeyError:
print("column label mismatch")
try:
frame.loc[0]
except KeyError:
print("row label 0 is absent")
print(frame.iloc[0, 0])
required = {"Amount "}
print("missing required columns:", sorted(required - set(frame.columns)))
Expected output:
["'Amount '"]
column label mismatch
row label 0 is absent
10
missing required columns: []
.loc selects labels; .iloc selects integer positions. A missing label raises KeyError, while an out-of-range positional access raises IndexError. Check column spelling, spaces, case and duplicate labels before renaming. Reindexing can deliberately add missing columns filled with unknown values, but it should not hide the absence of a required input. For a nested mapping, validate the shape at each level; a nonmapping value produces a different error and needs a different repair.