Raising Exceptions and Custom Errors
15 min · Beginner
Need help? Ask a tutor on WhatsApp (opens in a new tab)When your code detects invalid inputs or broken business rules, do not return dummy values like -1 or False. Raise an exception to halt execution and signal the failure explicitly.
Raising exceptions with raise
Raising an exception means creating an error on purpose with the raise keyword, to stop code that received invalid data.
Use the raise keyword followed by an exception class and an informative error message.
def set_discount(percentage): if not (0 <= percentage <= 100): raise ValueError(f"Invalid discount: {percentage}. Must be 0-100.") return percentage / 100
print(set_discount(15))Example 1 · Rejecting a bad discount
def set_discount(percent): if not 0 <= percent <= 100: raise ValueError("Discount must be between 0 and 100") return percent
try: set_discount(150)except ValueError as err: print(f"Rejected: {err}")Rejected: Discount must be between 0 and 100
What this code does
- The function checks its input and raises
ValueErrorwhen it is outside 0 to 100. - The caller catches it and prints the message.
Calling set_discount(150) immediately raises a ValueError with our clear explanation.
Defining custom exception classes
Custom exception is your own error type, a class that inherits from Exception. A clear name tells the reader which rule was broken.
Create your own custom exception by creating a class that inherits from Exception.
class InsufficientFundsError(Exception): """Raised when account balance is less than withdrawal amount.""" pass
def withdraw(balance, amount): if amount > balance: raise InsufficientFundsError(f"Cannot withdraw {amount} from {balance}") return balance - amountExample 2 · A custom error for a missing user
class UserNotFoundError(Exception): pass
def find_user(user_id, database): if user_id not in database: raise UserNotFoundError(f"User with ID {user_id} does not exist") return database[user_id]
db = {101: "Aditi", 102: "Kabir"}try: user = find_user(999, db)except UserNotFoundError as err: print(f"Handled: {err}")Handled: User with ID 999 does not exist
What this code does
- Defines a custom
UserNotFoundError. - Raises error when user ID 999 is missing from database.
- Catches domain error and outputs clean message.
Custom exceptions allow API callers to catch specific domain errors (e.g. except InsufficientFundsError:) cleanly.
Re-raising exceptions with bare raise
Re-raising is using raise with no arguments inside an except block to pass the same error up after handling part of it.
Use raise without arguments inside an except block to re-trigger the current exception after logging it.
def connect_database(): try: raise ConnectionError("DB unreachable") except ConnectionError as err: print(f"[LOG] Connection failure: {err}") # Re-raise to alert caller # raiseExample 3 · Log and pass the error up
def read_quantity(text): try: return int(text) except ValueError: print("Logging: bad quantity text") raise
try: read_quantity("two")except ValueError as err: print(f"Caller handled: {err}")Logging: bad quantity text Caller handled: invalid literal for int() with base 10: 'two'
What this code does
- The inner
exceptprints a log line, then a bareraisesends the same error up. - The outer
trycatches it and still sees the original message.
A bare raise re-emits the exact active exception with its original traceback intact.
Next step
Check your understanding
8 quick questions