Common Built‑in Exceptions
- Python ships with a rich hierarchy of exception classes; most automation errors fall into a small, predictable subset.
- All ordinary run‑time exceptions inherit from
Exception, but subclasses convey why something failed (e.g., file missing vs. wrong type).
- Catching overly broad bases like
Exception hides root causes and can mask bugs—prefer the narrowest class you can handle.
- Understanding the inheritance tree lets you decide when a single
except can cover many related problems (e.g., OSError).
import inspect, builtins
def show_tree(base, level=0, max_depth=1):
if level > max_depth:
return
for name, obj in vars(builtins).items():
if inspect.isclass(obj) and issubclass(obj, base) and obj is not base:
print("\t" * level + f"- {name}")
show_tree(obj, level + 1, max_depth)
show_tree(Exception, max_depth=1)
OSError Family: Filesystem & Network Issues
- Signals problems interacting with the operating system: files, permissions, sockets, paths.
- Subclasses such as
FileNotFoundError, PermissionError, IsADirectoryError, ConnectionRefusedError, and TimeoutError offer granularity.
- Catch individual subclasses when you can recover differently (create a missing file, prompt for sudo, retry a connection).
- A single
except OSError still groups all OS‑level failures when the response is the same (e.g., log and abort).
try:
with open('nonexistent.txt', 'r') as file:
content = file.read()
except FileNotFoundError as e:
print("File not found")
except PermissionError:
print("Permission denied when accessing resources.")
except OSError as os_err:
print(f"General OS error: {os_err}")
KeyError: Missing Dictionary Keys
- Raised when using
dict[key] with a key that is absent.
- Frequent in config loading, JSON parsing, or environment variable maps.
- Mitigation patterns:
dict.get(key, default), membership tests (if key in cfg), or a tailored except KeyError.
- Treats missing data distinctly from a wrong value (
ValueError) or wrong type (TypeError).
config = {"host": "server1", "port": 8080}
config2 = {"host": "server1", "port": 8080, "api-key": "12345"}
api_key = config.get("api-key", "")
print(f"API Key: {api_key}")
def call_endpoint(config, endpoint):
"""Calls the specified endpoint of the configured host.
Args:
config (dict(str)): Dict containing host, port, and api-key
endpoint (str): The endpoint to hit
"""
if "api-key" in config:
print(f"Making API call to endpoint {endpoint} with key: {config["api-key"]}")
else:
print("No api-key available, not possible to call API.")
def call_endpoint_exception(config, endpoint):
"""Calls the specified endpoint of the configured host.
Args:
config (dict(str)): Dict containing host, port, and api-key
endpoint (str): The endpoint to hit
"""
try:
print(f"Making API call to endpoint {endpoint} with key: {config["api-key"]}")
except KeyError as missing_key:
print(f"No required key {missing_key} available, not possible to call API.")
call_endpoint(config, "/users")
call_endpoint(config2, "/users")
call_endpoint_exception(config, "/users")
call_endpoint_exception(config2, "/users")
IndexError: Sequence Index Out of Bounds
- Triggered when list/tuple indices fall outside the valid range: negative beyond the left edge or ≥
len(seq).
- Common during iterative processing of dynamic lists or user‑provided indexes.
- Prevent with bounds checks (
if i < len(seq)), safe iteration (for item in seq:), or catch and default.
- Signals "wrong position" rather than "wrong content".
servers = ["web01", "web02"]
i = 2
if i < len(servers):
print(servers[i])
try:
print(servers[i])
except IndexError as e:
print(f"Index error: {e}. List length is {len(servers)}")
ValueError vs. TypeError
- ValueError: argument type is acceptable but content/value is invalid (e.g.,
int("abc")).
- TypeError: operation applied to an object of the wrong type altogether (e.g.,
len(5) or "a" + 3).
- Distinguishing them clarifies whether to validate content or convert types.
- Catch them separately to craft precise user feedback.
try:
port = int("http") # ValueError, since literal must be a valid base-10 value
except ValueError as e:
print(f"Bad numeric string: {e}")
try:
total = "Errors: " + 5
except TypeError as e:
print(f"Type mismatch: {e}")
AttributeError: Missing Object Member
- Raised when an attribute or method doesn't exist on the object referenced.
- Often results from typos, unexpected
None, or polymorphic functions returning different types.
- Defensive techniques:
hasattr(obj, "attr"), if obj is not None:, or narrow except AttributeError.
- Conveys "object of this type doesn’t support that capability".
class Calculator:
def add(self, a, b):
return a + b
calc = Calculator()
if hasattr(calc, "subtract"):
print(calc.subtract(10, 5))
else:
print("Object has no attribute 'subtract'")
try:
print(calc.subtract(10, 5))
except AttributeError as e:
print(f"AttributeError caught: {e}.")
try:
print(calc.result)
except AttributeError as e:
print(f"AttributeError caught: {e}.")
ImportError / ModuleNotFoundError
- Raised when an
import statement cannot locate a module/package.
ModuleNotFoundError (Python 3.6+) is the specific subclass; catching ImportError also covers it.
- Causes: misspelling, package not installed, wrong virtual environment, or PYTHONPATH issues.
- Typical handling logs instructions and aborts early to avoid cascading failures.
try:
import non_existent_lib
except ModuleNotFoundError as e:
print(f"Import failed: {e}. Is the library installed and the correct venv active?")