Implement defensive null checking to prevent NoneType errors, KeyError, and IndexError exceptions. When accessing dictionaries, collections, or optional values, verify existence before use.

For dictionary access:

# Unsafe - may raise KeyError:
message = event["data"]["payload"]["message"]

# Safe - uses default value if key missing:
message = event["data"]["payload"].get("message")
# With explicit default:
message = event["data"]["payload"].get("message", "Unknown")

For collections:

# Unsafe - may raise IndexError:
first_item = my_list[0]

# Safe - check before access:
if isinstance(my_list, list) and my_list:
    first_item = my_list[0]

For optional attributes:

# Unsafe - may raise AttributeError or work unexpectedly:
if self.project_ids:  # This passes if project_ids is empty list but fails if None
    result = process_data(self.project_ids)

# Safe - explicit type check:
if self.project_ids is not None:
    result = process_data(self.project_ids)

For inconsistent external data:

# Defensive type handling:
timestamp_raw = event.get("timestamp_ms", 0)
if isinstance(timestamp_raw, str):
    try:
        dt = datetime.fromisoformat(timestamp_raw.replace("Z", "+00:00"))
        timestamp = dt.timestamp() * 1000  # Convert to milliseconds
    except (ValueError, AttributeError):
        timestamp = 0.0
else:
    timestamp = float(timestamp_raw)