Exceptions cheatsheet.
Basic
try:
result = risky()
except ValueError as e:
log.error("bad value", error=str(e))
except (KeyError, TypeError) as e:
log.error("type/key error")
except Exception:
log.exception("unexpected") # logs with stack trace
raise
finally:
cleanup()
try/except/else
try:
result = risky()
except Error:
handle()
else:
# runs if no exception
use(result)
else clarifies “use(result) only on success.”
Raise
raise ValueError("bad input")
raise ValueError("bad input") from original_exc
from: chains exceptions. Output shows both.
try:
parse(...)
except ValueError as e:
raise BusinessError("can't parse user") from e
Suppressing original
raise ValueError("new") from None
Hides the original. Use when you’ve handled it but want a clean stack trace.
Re-raise
try:
...
except Exception:
log.exception("...")
raise # re-raises current
Custom exception hierarchy
class AppError(Exception):
"""Base for all app errors."""
class NotFoundError(AppError): ...
class ValidationError(AppError): ...
class AuthError(AppError): ...
class PermissionError(AuthError): ...
# Usage
try:
...
except AppError as e:
# catches all app errors
pass
except PermissionError:
# more specific catch goes first
pass
Exception arguments
class HttpError(Exception):
def __init__(self, status: int, message: str):
self.status = status
self.message = message
super().__init__(f"{status}: {message}")
raise HttpError(404, "not found")
ExceptionGroup (3.11+)
try:
async with asyncio.TaskGroup() as tg:
tg.create_task(a())
tg.create_task(b())
except* ValueError as eg:
log.error("value errors", count=len(eg.exceptions))
except* TypeError as eg:
log.error("type errors")
except* matches inside the group. Multiple except* can run.
Construct manually
group = ExceptionGroup("multi-error", [ValueError("a"), KeyError("b")])
raise group
with suppress
from contextlib import suppress
with suppress(FileNotFoundError, PermissionError):
os.remove("file.txt")
Cleaner than try/except for “ignore these errors.”
Assertion (not for prod errors!)
assert x > 0, "x must be positive"
assert is stripped with python -O. Use for internal invariants, NOT input validation.
Common exceptions
Exception
ArithmeticError
ZeroDivisionError
LookupError
KeyError
IndexError
ValueError
TypeError
AttributeError
NameError
FileNotFoundError
PermissionError
OSError
IOError (alias for OSError)
TimeoutError
RuntimeError
StopIteration
StopAsyncIteration
KeyboardInterrupt
SystemExit
KeyboardInterrupt and SystemExit don’t inherit from Exception — they inherit from BaseException.
except: vs except Exception:
try: ...
except: ... # BAD: catches KeyboardInterrupt, SystemExit
except Exception: ... # GOOD: catches everything app-level
Never bare except: — you’ll block Ctrl+C.
Logging exceptions
try:
...
except Exception:
log.exception("operation failed", extra={"context": "..."})
log.exception automatically captures the current exception’s stack trace. Use only inside except.
Chaining
try:
a()
except ValueError as e:
try:
fallback()
except KeyError as e2:
raise RuntimeError("both failed") from e2
# Shows "while handling KeyError, RuntimeError was raised"
cause vs context
raise X from Ysets__cause__ = Y— explicit chain.- Exception raised in another except sets
__context__— implicit chain.
Try/finally pattern (no except)
try:
resource = acquire()
use(resource)
finally:
release(resource)
Equivalent to with for resources.
Async exceptions
Same syntax in async functions:
async def handler():
try:
await fetch()
except httpx.TimeoutException:
...
CancelledError needs care:
async def worker():
try:
await long_op()
except asyncio.CancelledError:
await cleanup()
raise # re-raise!
Custom str
class ApiError(Exception):
def __init__(self, status, body):
self.status, self.body = status, body
def __str__(self):
return f"API {self.status}: {self.body}"
Common mistakes
- Bare
except:— catches KeyboardInterrupt; user can’t kill process. - Swallowing exceptions silently — no log, no re-raise.
assertfor user input — stripped with -O.raise Exception("...")— too generic; create specific types.- Catching too broadly then handling some cases — others silently lost.
Read this next
If you want my exception hierarchy + error envelope library, it’s at rajpoot.dev .
Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .