How to check for None and raise helpful errors in Python

A defensive function that explicitly validates data, keys, and values — raising descriptive ValueError and KeyError exceptions before returning a result.

Easy Python 3.9+ Aug 9, 2026 Errors & debugging 15 views 0 copies

Python code

19 lines
Python 3.9+
def get_value(data, key):
    if data is None:
        raise ValueError("data cannot be None")
    if key not in data:
        raise KeyError(f"key '{key}' not found in data")
    result = data[key]
    if result is None:
        raise ValueError(f"value for key '{key}' is None")
    return result


if __name__ == "__main__":
    sample = {"name": "Alice", "age": None}
    for key in ("name", "age", "missing"):
        try:
            value = get_value(sample, key)
            print(f"{key}: {value}")
        except (ValueError, KeyError) as e:
            print(f"{key}: ERROR: {e}")

Output

stdout
name: Alice
age: ERROR: value for key 'age' is None
missing: ERROR: key 'missing' not found in data

How it works

The get_value function runs three explicit checks: whether data itself is None, whether the requested key exists, and whether the associated value is None. Each failure raises a distinct exception with a human-readable message, making bugs easier to trace. Early returns and explicit raise statements keep the control flow simple and understandable. This pattern is deterministic and testable — no silent None propagation or unexpected KeyError deep in your call stack.

Common mistakes

  • Forgetting to raise a custom message for clarity
  • Checking values for None but not guarding against the data container itself
  • Using `if data:` instead of `if data is None:` — empty dicts are falsy and would incorrectly raise
  • Neglecting to handle the key-not-found case before the None-value check

Variations

  1. Use `data.get(key)` with a sentinel default and check if it's the sentinel to distinguish missing keys from None values
  2. Define a custom exception subclass (e.g., `MissingKeyError(KeyError)`) for more refined error handling by callers

Real-world use cases

  • Validating user-provided config dictionaries before passing them to a connection pool or database engine.
  • Wrapping a third-party API response dict so missing or null fields fail fast with readable errors.
  • Sanitizing JSON payloads from webhooks or message queues before mapping them into internal models.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Errors & debugging

Related tutorials and quizzes for this topic.