Maybe I missed the question, but why not:

class MyException(Exception):
    pass

To override something (or pass extra args), do this:

class ValidationError(Exception):
    def __init__(self, message, errors):            
        # Call the base class constructor with the parameters it needs
        super().__init__(message)
            
        # Now for your custom code...
        self.errors = errors

That way you could pass dict of error messages to the second param, and get to it later with e.errors.

In Python 2, you have to use this slightly more complex form of super():

super(ValidationError, self).__init__(message)
Answer from gahooa on Stack Overflow
🌐
Python
docs.python.org › 3 › builtins › exceptions.html
Built-in Exceptions — Python 3.14.7 documentation
In Python, all exceptions must be instances of a class that derives from BaseException. In a try statement with an except clause that mentions a particular class, that clause also handles any excep...
🌐
Python documentation
docs.python.org › 3 › tutorial › errors.html
8. Errors and Exceptions — Python 3.14.7 documentation
Exception classes can be defined which do anything any other class can do, but are usually kept simple, often only offering a number of attributes that allow information about the error to be extracted by handlers for the exception.
Top answer
1 of 16
2073

Maybe I missed the question, but why not:

class MyException(Exception):
    pass

To override something (or pass extra args), do this:

class ValidationError(Exception):
    def __init__(self, message, errors):            
        # Call the base class constructor with the parameters it needs
        super().__init__(message)
            
        # Now for your custom code...
        self.errors = errors

That way you could pass dict of error messages to the second param, and get to it later with e.errors.

In Python 2, you have to use this slightly more complex form of super():

super(ValidationError, self).__init__(message)
2 of 16
760

With modern Python Exceptions, you don't need to abuse .message, or override .__str__() or .__repr__() or any of it. If all you want is an informative message when your exception is raised, do this:

class MyException(Exception):
    pass

raise MyException("My hovercraft is full of eels")

That will give a traceback ending with MyException: My hovercraft is full of eels.

If you want more flexibility from the exception, you could pass a dictionary as the argument:

raise MyException({"message":"My hovercraft is full of animals", "animal":"eels"})

However, to get at those details in an except block is a bit more complicated. The details are stored in the args attribute, which is a list. You would need to do something like this:

try:
    raise MyException({"message":"My hovercraft is full of animals", "animal":"eels"})
except MyException as e:
    details = e.args[0]
    print(details["animal"])

It is still possible to pass in multiple items to the exception and access them via tuple indexes, but this is highly discouraged (and was even intended for deprecation a while back). If you do need more than a single piece of information and the above method is not sufficient for you, then you should subclass Exception as described in the tutorial.

class MyError(Exception):
    def __init__(self, message, animal):
        self.message = message
        self.animal = animal
    def __str__(self):
        return self.message
🌐
Python
python.org › doc › essays › stdexceptions
Standard Exception Classes in Python 1.5 | Python.org
Some related exceptions are grouped together using an intermediate class derived from StandardError; this makes it possible to catch several different exceptions in one except clause, without using the tuple notation. We looked into introducing more groups of related exceptions, but couldn't decide on the best grouping. In a language as dynamic as Python, it's hard to say whether TypeError is a "program error", a "runtime error" or an "environmental error", so we decided to leave it undecided.
🌐
Programiz
programiz.com › python-programming › user-defined-exception
How to Define Custom Exceptions in Python? (With Examples)
In Python, we can define custom exceptions by creating a new class that is derived from the built-in Exception class.
🌐
Honeybadger
honeybadger.io › blog › a-guide-to-exception-handling-in-python
The ultimate guide to Python exception handling - Honeybadger Developer Blog
March 28, 2025 - Error code: 1001 Custom Exception occurred: Division by zero is not allowed. In the code above, the CustomException class is defined, inheriting from the base Exception class. It has an additional attribute, error_code, which is set to 1001 in the constructor (__init__ method).
🌐
Python Tutorial
pythontutorial.net › home › python oop › python exceptions
Python Exceptions
March 28, 2025 - Python exceptions are objects of classes, which are the subclasses of the BaseException class.
Find elsewhere
🌐
GeeksforGeeks
geeksforgeeks.org › python › built-exceptions-python
Python Built-in Exceptions - GeeksforGeeks
... Explanation: Here, we forcefully raise a BaseException. Since we catch it in the except block, message is printed instead of the program crashing. Exception class is the base for all non-exit exceptions.
Published: April 18, 2026
Top answer
1 of 3
11

naming booleans

    def __init__( ... , info: bool = False):

That's just weird. It looks like we're going to have some descriptive information supplied there, and then it turns out it's a flag.

Please use a name like want_info, which suggests it's a flag. Or better, use the conventional name for this: verbose

use Path for a path

        self.file_name = "<unknown file>"

Typing that as str seems unfortunate; better to make it a Path.

Also, if we really need to represent "unknown", then None would be the usual approach. It would indicate that we do not yet have a valid file name.

I do appreciate that the constructor always exits with the same set of object attributes defined, even in the event of an error.

extra refcount decrement

This seems pointless:

                del frame_error
                del frame_current

It looks like java code that assigns frame_current = null; to ensure eventual garbage collection. And yes, I understand we don't want spurious references keeping a frame alive for "too long".

Their refcounts will go to zero in a couple of lines when we return. It's not like it matters whether they exist during the linecache.getline() call. Simply elide the del statements.

spurious try

Checking whether currentframe() gave us None is essentially asking "are we running under cPython?", which seems legitimate. But then the try seems to be trapping AttributeError in case .co_name or similar does not exist. That sounds like a "cannot happen" case to me.

Please use except AttributeError: if that was the true concern.

And in any event the frame_{error,current} refcounts shall be decremented to zero upon leaving this scope, so no need for try / finally.

consistent newline

It seems unfortunate that str(exc) will end with "\n" in the verbose case but not in the default case.


motivation

class PayrollError(Exception):
    pass

class NoFundsError(PayrollError):
    pass

class EmployeeIdNotFoundError(PayrollError):
    pass

or if it’s something unnecessary or not recommended

Generally, I don't get why an app author would want to raise your CustomError. I mean, apps routinely define an app-specific hierarchy such as the example I supplied. Once we have seen that calling code can actually retry / recover from certain conditions, then defining something more specific than ValueError makes sense. And the tree of error classes conveniently lets a caller catch several things or just one.

But the OP code is mostly concerned with inspecting what's on the call stack. By default the interpreter displays a nice backtrace already. It feels like the code we see here belongs up in the app's top-level default error handler which is responsible for logging what happened.

As a maintainer, I feel this code would hide important details from me. When something has gone horribly wrong in an unanticipated way, I really want to see all the details of a backtrace, not just the subset that an app author anticipated would be relevant.

If there is some other audience for these diagnostic messages, such as web client end users, then that should be explicitly written down in """docstrings""" or # comments.

2 of 3
7

I have a couple reservations here. In the provided example, CustomError is used as a snap-in replacement for ValueError. The error message already makes it clear where the error comes from, because it is set by the programmer. So the exception handler does not provide a lot of additional insight.

Should you even raise an exception in this case? I find that debatable, because you can easily prevent the error in the first place by checking the value. In a real scenario, you might want to perform even more checks.

That being said, raising an exception is useful when you want to add an entry to the error logs, or when you want some corrective action to take place, like a cleanup routine (even though a context manager or a Finally clause can take care of that).

Minor points

Some statements can be simplified just a little:

self.source_line = linecache.getline(self.file_name,self.line).strip()
        if not self.source_line:
            self.source_line = "<unavailable

Slightly more succinct:

self.source_line = linecache.getline(self.file_name,self.line).strip() or "<unavailable source>"

However, there is a possible flaw here. If linecache.getline returns None, then the .strip you are applying could fail and raise an exception. But wait, let's look at the docs, because I admit I am not familiar with this lib. Sounds like you are in the clear here:

Get line lineno from file named filename. This function will never raise an exception — it will return '' on errors (the terminating newline character will be included for lines that are found).

I believe the frame object properties eg f_lineno etc should all be present, so hopefully no surprises here.

Instead of:

self.file_name = "<unknown file>"
self.func_name = "<unknown func>"

I would use None as a value. That simplifies parsing, and makes it clear that the value is not initialized or not yet known. The programmer retrieving these values from the exception can still reformat the error message as desired.

In __repr__ you use self.__class__.__name__ to identify your class, good idea. You can do the same in the __str__ method.

Stack trace

In more complex situations, the full stack trace is really helpful to have the context of the error, so that the programmer can dig hard into the logs and fix the issue. Perhaps you should consider making it available as an option. The idea should be to add more context and insight, not suppress useful information.

If the intention is really to generalize usage of this class, as an all-purpose exception handler, this could be problematic because we may want to handle exceptions differently, depending on their type. Some exceptions are recoverable, like transient network errors, whereas other exceptions are more fatal and point to a flaw in the program that cannot be easily managed.

🌐
Derlin
blog.derlin.ch › diving-deeper-into-python-exceptions
Diving Deeper into Python Exceptions - DERLIN.
January 9, 2024 - I had no clue how to do this except to override the Token class in my codebase. When I asked my boss about this, he looked at me and said: “just use __context__”. Huh? Never heard of it. I started digging, and long story short: he was right. This was the perfect solution. Those small discoveries happened a lot lately, and I wanted to share them. If this intrigues you, keep reading! ... Formalised in PEP 3134 (I love PEPs), exceptions in Python 3 have three dunder attributes that provide information about the context in which they were raised: __cause__, __context__ and __suppress_context__.
🌐
TutorialsPoint
tutorialspoint.com › object_oriented_python › object_oriented_python_exception_classes.htm
Exception and Exception Classes
When something unusual occurs in your program and you wish to handle it using the exception mechanism, you throw an exception. The keywords try and except are used to catch exceptions.
🌐
Towards Data Science
towardsdatascience.com › home › latest › how to define custom exception classes in python
How to Define Custom Exception Classes in Python | Towards Data Science
March 5, 2025 - This is just a syntax help that Python adds when you raise an exception · In the second example, MyCustomError is passed with a string argument of 'We have a problem'. This is set as the message attribute in the object and printed in the error message when the exception is raised. The code for the MyCustomError exception class can be found here.
🌐
W3Schools
w3schools.com › python › python_ref_exceptions.asp
Python Built-in Exceptions
The table below shows built-in exceptions that are usually raised in Python.
🌐
Medium
martinxpn.medium.com › exception-hierarchy-python-58-100-days-of-python-9d8585e6569b
Exception Hierarchy Python (58/100 Days of Python) | by Martin Mirakyan | Medium
April 10, 2023 - This means that every exception in Python is an instance of BaseException or one of its subclasses. The BaseException class is the top-level class in the exception hierarchy. It provides some common methods that all exceptions can use, such ...
🌐
GeeksforGeeks
geeksforgeeks.org › python › user-defined-exceptions-python-examples
User-defined Exceptions in Python with Examples - GeeksforGeeks
InvalidAgeError class inherits from Exception. It defines an __init__ method to accept age and message. The __str__ method returns a readable string representation of the error. In set_age(), if the age is outside the valid range (0–120), the exception is raised. The try-except block catches the exception and prints the error message. When we create a custom exception, we subclass Python’s built-in Exception class (or a subclass like ValueError, TypeError, etc.).
Published: February 12, 2026
🌐
Python Module of the Week
pymotw.com › 2 › exceptions
exceptions – Built-in error classes - Python Module of the Week
Base class for built-in exceptions used in the standard library. Base class for math-related errors. Base class for errors raised when something can’t be found. Base class for errors that come from outside of Python (the operating system, filesystem, etc.).
🌐
Real Python
realpython.com › ref › builtin-exceptions › exception
Exception | Python’s Built-in Exceptions – Real Python
Exception is a built-in exception that serves as the base class for all built-in exceptions except for system-exiting exceptions. It’s itself a direct subclass of BaseException.
🌐
Reddit
reddit.com › r/pythontips › defining custom exception classes in python
r/pythontips on Reddit: Defining CUstom Exception Classes in Python
January 23, 2021 -

Hello everyone,

This week, I worked through the various aspects of Exception Handling in Python. I have to admit, I never thought I would have so much fun learning so many new things about handling Python exceptions and especially defining custom exception classes. So I decided to offer my 2 cents on the topic.

Check out my video on Defining Custom Exception Class and its advantages here.

If you prefer reading blogs, you can find it here.

All discussions are welcome.

🌐
Python
docs.python.org › 3.3 › library › exceptions.html
5. Built-in Exceptions — Python 3.3.7 documentation
In Python, all exceptions must be instances of a class that derives from BaseException. In a try statement with an except clause that mentions a particular class, that clause also handles any exception classes derived from that class (but not exception classes from which it is derived).