Custom Exceptions in Python – Create Your Own Exceptions

Introduction

Python provides a rich set of built-in exceptions such as ValueError, TypeError, FileNotFoundError, and ZeroDivisionError to handle common errors. However, in real-world applications, built-in exceptions may not always be sufficient to represent specific business rules or application-specific errors.

Custom exceptions allow developers to create their own error types that are meaningful, readable, and easier to maintain.

For example, imagine you’re developing a banking application and want to raise an error when a withdrawal amount exceeds the available balance. Using a generic exception like ValueError works, but it does not clearly describe the actual problem. This is where custom exceptions become useful.

What are Custom Exceptions in Python?

A custom exception is a user-defined exception class created by inheriting from Python’s built-in Exception class.

Custom exceptions help developers:

  • Define application-specific errors
  • Improve code readability
  • Make debugging easier
  • Provide meaningful error messages
  • Separate business logic errors from system errors

Instead of raising generic exceptions, you can create custom exceptions that clearly describe the problem.

For example:


class InsufficientBalanceError(Exception):
    pass

Now you can use this exception whenever a user tries to withdraw more money than available.

Why Use Custom Exceptions?

Custom exceptions offer several advantages:

1. Better Readability


raise InsufficientBalanceError("Insufficient funds")

is much clearer than:


raise Exception("Error")

2. Easier Debugging

Developers can immediately identify the source and type of error.

3. Better Error Handling

Different exceptions can be handled differently.

4. Business Logic Validation

Custom exceptions are useful for enforcing rules specific to your application.

Examples:

  • Invalid student records
  • Insufficient bank balance
  • Invalid product quantity
  • Unauthorized user access
  • Invalid file format

Syntax

Basic syntax:


class CustomException(Exception):
    pass

Raising the exception:


raise CustomException("Something went wrong")

Handling the exception:


try:
    raise CustomException("Something went wrong")
except CustomException as e:
    print(e)

Creating Your First Custom Exception

Let’s create a simple custom exception.


class AgeError(Exception):
    pass
age = 15
if age < 18:
    raise AgeError("You must be at least 18 years old")

Output:

AgeError: You must be at least 18 years old

Explanation:

  • AgeError inherits from Exception.
  • The exception is raised when age is less than 18.
  • Python displays the custom error message.

Custom Exception with Try-Except


class AgeError(Exception):
    pass
try:
    age = 16
    if age < 18:
        raise AgeError("Age must be 18 or above")
except AgeError as e:
    print("Error:", e)

Output:

Error: Age must be 18 or above

Explanation:

The custom exception is caught and handled using the except block.

Example 1: Banking System

A banking application should prevent withdrawals beyond the available balance.


class InsufficientBalanceError(Exception):
    pass
balance = 5000
withdraw = 7000
if withdraw > balance:
    raise InsufficientBalanceError(
        "Insufficient account balance"
    )

Output:

InsufficientBalanceError:
Insufficient account balance

This makes the error much more meaningful than a generic exception.

Example 2: Student Management System


class InvalidMarksError(Exception):
    pass
marks = 120
if marks > 100:
    raise InvalidMarksError(
        "Marks cannot exceed 100"
    )

Output:

InvalidMarksError:
Marks cannot exceed 100

Example 3: E-commerce Application


class OutOfStockError(Exception):
    pass
stock = 0
if stock == 0:
    raise OutOfStockError(
        "Product is currently unavailable"
    )

Output:

OutOfStockError:
Product is currently unavailable

Custom Exception with Constructor

Custom exceptions can accept additional information.


class InvalidSalaryError(Exception):
    def __init__(self, salary):
        self.salary = salary
        self.message = f"Invalid salary: {salary}"
        super().__init__(self.message)
raise InvalidSalaryError(-5000)

Output:

InvalidSalaryError:
Invalid salary: -5000

Explanation:

  • The constructor receives the invalid salary.
  • A custom message is generated.
  • The message is passed to the parent class.

Multiple Custom Exceptions

Applications often require multiple exception types.


class InvalidUsernameError(Exception):
    pass
class InvalidPasswordError(Exception):
    pass
username = ""
password = "123"
if username == "":
    raise InvalidUsernameError(
        "Username cannot be empty"
    )
if len(password) < 6:
    raise InvalidPasswordError(
        "Password too short"
    )

This approach makes error handling more organized.

Real-Life Example: Online Examination System

Suppose you’re building an online examination platform.

Requirements:

  • Student must be registered.
  • Exam must be active.
  • Marks must be valid.

class StudentNotRegisteredError(Exception):
    pass
class ExamClosedError(Exception):
    pass
class InvalidMarksError(Exception):
    pass
registered = False
exam_active = True
marks = 120
if not registered:
    raise StudentNotRegisteredError(
        "Student is not registered"
    )
if not exam_active:
    raise ExamClosedError(
        "Exam is closed"
    )
if marks > 100:
    raise InvalidMarksError(
        "Marks cannot exceed 100"
    )

Benefits:

  • Errors are easy to understand.
  • Different errors can be handled separately.
  • The application becomes easier to maintain.

Custom Exceptions Hierarchy

You can create a base exception and inherit other exceptions from it.


class ApplicationError(Exception):
    pass
class LoginError(ApplicationError):
    pass
class PaymentError(ApplicationError):
    pass

Usage:


try:
    raise LoginError("Invalid login")
except ApplicationError as e:
    print(e)

Output:

Invalid login

This approach is common in large applications.

Raising Custom Exceptions Manually


class InvalidEmailError(Exception):
    pass
email = "abcgmail.com"
if "@" not in email:
    raise InvalidEmailError(
        "Email format is invalid"
    )

Output:

InvalidEmailError:
Email format is invalid

Best Practices for Custom Exceptions

1. Use Meaningful Names

Good:


class InvalidOrderError(Exception):
    pass

Bad:


class Error(Exception):
    pass

2. Inherit from Exception

Always inherit from Exception.

Correct:


class MyError(Exception):
    pass

3. Provide Helpful Messages


raise InvalidOrderError(
    "Order quantity cannot be negative"
)

4. Create Exception Hierarchies

For large projects:


class ApplicationError(Exception):
    pass

and then inherit specific exceptions.

5. Avoid Excessive Custom Exceptions

Create custom exceptions only when they provide meaningful value.

Common Mistakes

1. Not Inheriting from Exception

Incorrect:


class MyError:
    pass

Correct:


class MyError(Exception):
    pass

2. Using Generic Exception Everywhere

Incorrect:


raise Exception("Error")

Better:


raise InvalidOrderError(
    "Invalid order quantity"
)

3. Creating Too Many Exceptions

Avoid creating separate exceptions for trivial cases.

4. Ignoring Error Messages

Incorrect:


raise InvalidMarksError

Better:


raise InvalidMarksError(
    "Marks cannot exceed 100"
)

5. Not Handling Custom Exceptions

Incorrect:


raise InvalidMarksError("Error")

Better:


try:
    raise InvalidMarksError("Error")
except InvalidMarksError as e:
    print(e)

Conclusion

Custom exceptions are a powerful feature in Python that allows developers to create meaningful and application-specific error types.

By inheriting from the Exception class, providing descriptive names, and using informative error messages, developers can build robust and maintainable applications. Whether you’re developing banking software, e-commerce platforms, student management systems, or enterprise applications, custom exceptions play a vital role in creating professional-quality Python programs.

Related Python Tutorials