Categories
exception python

Manually raising (throwing) an exception in Python

2921

How do I raise an exception in Python so that it can later be caught via an except block?

0

    3839

    How do I manually throw/raise an exception in Python?

    Use the most specific Exception constructor that semantically fits your issue.

    Be specific in your message, e.g.:

    raise ValueError('A very specific bad thing happened.')
    

    Don’t raise generic exceptions

    Avoid raising a generic Exception. To catch it, you’ll have to catch all other more specific exceptions that subclass it.

    Problem 1: Hiding bugs

    raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs.
    

    For example:

    def demo_bad_catch():
        try:
            raise ValueError('Represents a hidden bug, do not catch this')
            raise Exception('This is the exception you expect to handle')
        except Exception as error:
            print('Caught this error: ' + repr(error))
    
    >>> demo_bad_catch()
    Caught this error: ValueError('Represents a hidden bug, do not catch this',)
    

    Problem 2: Won’t catch

    And more specific catches won’t catch the general exception:

    def demo_no_catch():
        try:
            raise Exception('general exceptions not caught by specific handling')
        except ValueError as e:
            print('we will not catch exception: Exception')
     
    
    >>> demo_no_catch()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 3, in demo_no_catch
    Exception: general exceptions not caught by specific handling
    

    Best Practices: raise statement

    Instead, use the most specific Exception constructor that semantically fits your issue.

    raise ValueError('A very specific bad thing happened')
    

    which also handily allows an arbitrary number of arguments to be passed to the constructor:

    raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz') 
    

    These arguments are accessed by the args attribute on the Exception object. For example:

    try:
        some_code_that_may_raise_our_value_error()
    except ValueError as err:
        print(err.args)
    

    prints

    ('message', 'foo', 'bar', 'baz')    
    

    In Python 2.5, an actual message attribute was added to BaseException in favor of encouraging users to subclass Exceptions and stop using args, but the introduction of message and the original deprecation of args has been retracted.

    Best Practices: except clause

    When inside an except clause, you might want to, for example, log that a specific type of error happened, and then re-raise. The best way to do this while preserving the stack trace is to use a bare raise statement. For example:

    logger = logging.getLogger(__name__)
    
    try:
        do_something_in_app_that_breaks_easily()
    except AppError as error:
        logger.error(error)
        raise                 # just this!
        # raise AppError      # Don't do this, you'll lose the stack trace!
    

    Don’t modify your errors… but if you insist.

    You can preserve the stacktrace (and error value) with sys.exc_info(), but this is way more error prone and has compatibility problems between Python 2 and 3, prefer to use a bare raise to re-raise.

    To explain – the sys.exc_info() returns the type, value, and traceback.

    type, value, traceback = sys.exc_info()
    

    This is the syntax in Python 2 – note this is not compatible with Python 3:

    raise AppError, error, sys.exc_info()[2] # avoid this.
    # Equivalently, as error *is* the second object:
    raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]
    

    If you want to, you can modify what happens with your new raise – e.g. setting new args for the instance:

    def error():
        raise ValueError('oops!')
    
    def catch_error_modify_message():
        try:
            error()
        except ValueError:
            error_type, error_instance, traceback = sys.exc_info()
            error_instance.args = (error_instance.args[0] + ' <modification>',)
            raise error_type, error_instance, traceback
    

    And we have preserved the whole traceback while modifying the args. Note that this is not a best practice and it is invalid syntax in Python 3 (making keeping compatibility much harder to work around).

    >>> catch_error_modify_message()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 3, in catch_error_modify_message
      File "<stdin>", line 2, in error
    ValueError: oops! <modification>
    

    In Python 3:

    raise error.with_traceback(sys.exc_info()[2])
    

    Again: avoid manually manipulating tracebacks. It’s less efficient and more error prone. And if you’re using threading and sys.exc_info you may even get the wrong traceback (especially if you’re using exception handling for control flow – which I’d personally tend to avoid.)

    Python 3, Exception chaining

    In Python 3, you can chain Exceptions, which preserve tracebacks:

    raise RuntimeError('specific message') from error
    

    Be aware:

    • this does allow changing the error type raised, and
    • this is not compatible with Python 2.

    Deprecated Methods:

    These can easily hide and even get into production code. You want to raise an exception, and doing them will raise an exception, but not the one intended!

    Valid in Python 2, but not in Python 3 is the following:

    raise ValueError, 'message' # Don't do this, it's deprecated!
    

    Only valid in much older versions of Python (2.4 and lower), you may still see people raising strings:

    raise 'message' # really really wrong. don't do this.
    

    In all modern versions, this will actually raise a TypeError, because you’re not raising a BaseException type. If you’re not checking for the right exception and don’t have a reviewer that’s aware of the issue, it could get into production.

    Example Usage

    I raise Exceptions to warn consumers of my API if they’re using it incorrectly:

    def api_func(foo):
        '''foo should be either 'baz' or 'bar'. returns something very useful.'''
        if foo not in _ALLOWED_ARGS:
            raise ValueError('{foo} wrong, use "baz" or "bar"'.format(foo=repr(foo)))
    

    Create your own error types when apropos

    “I want to make an error on purpose, so that it would go into the except”

    You can create your own error types, if you want to indicate something specific is wrong with your application, just subclass the appropriate point in the exception hierarchy:

    class MyAppLookupError(LookupError):
        '''raise this when there's a lookup error for my app'''
    

    and usage:

    if important_key not in resource_dict and not ok_to_be_missing:
        raise MyAppLookupError('resource is missing, and that is not ok.')
    

    7

    • try: raise ValueError(‘error’) except ValueError as e: print(‘we will catch exception: Exception’,str(e)) #is the best solution

      Jan 15, 2021 at 11:49


    • 1

      @SharathBJ you’re raising a ValueError and reporting it as the type, Exception, and that’s an unnecessary loss of precision. repr(e) will at least report the type for you.

      Jan 15, 2021 at 16:18

    • Where’s the official documentation that shows you can pass in a message when raising an exception? ex: raise TypeError("my message")

      Feb 5, 2021 at 19:50


    • 1

      @GabrielStaples here’s the docs on instantiation args: docs.python.org/3/library/exceptions.html#BaseException.args

      Feb 5, 2021 at 21:56

    • @AaronHall, ah, I see. I didn’t realize the exception type, such as TypeError, was a call to a class constructor! Makes sense now. The message is therefore a common constructor arg for error-type classes.

      Feb 5, 2021 at 23:34


    563

    Don’t do this. Raising a bare Exception is absolutely not the right thing to do; see Aaron Hall’s excellent answer instead.

    It can’t get much more Pythonic than this:

    raise Exception("I know Python!")
    

    Replace Exception with the specific type of exception you want to throw.

    See the raise statement documentation for Python if you’d like more information.

    14

    • 101

      No please! This removes the potential to be specific about what you catch. It is ENTIRELY the wrong way to do it. Take a look at Aaron Hall’s excellent answer instead of this one. It’s times like this I wish I could give more than one downvote per answer.

      Jan 21, 2015 at 22:23


    • 44

      @PeterR It’s equally terrible that it has so few downvotes. To ANYBODY reading this answer, DO NOT DO THIS EVER! The correct answer is Aaron Hall’s one.

      Feb 16, 2015 at 9:38

    • 17

      @CharlieParker There is. It’s the first part of Aaron Hall’s answer.

      – Dinei

      Feb 24, 2017 at 12:42

    • 12

      @codeforester maybe it’s because it’s answering the question.

      – Daniel F.

      Apr 13, 2018 at 7:09

    • 12

      This answer is still here because many experienced developers disagree with use of specialized exception classes. I wish I could downvote comments.

      – ctpenrose

      Oct 19, 2018 at 23:50

    79

    In Python 3 there are four different syntaxes for raising exceptions:

    1. raise exception
    2. raise exception (args)
    3. raise
    4. raise exception (args) from original_exception

    1. Raise exception vs. 2. raise exception (args)

    If you use raise exception (args) to raise an exception then the args will be printed when you print the exception object – as shown in the example below.

      # Raise exception (args)
        try:
            raise ValueError("I have raised an Exception")
        except ValueError as exp:
              print ("Error", exp)     # Output -> Error I have raised an Exception
    
    
      # Raise exception
        try:
            raise ValueError
        except ValueError as exp:
              print ("Error", exp)     # Output -> Error
    

    3. Statement raise

    The raise statement without any arguments re-raises the last exception.

    This is useful if you need to perform some actions after catching the exception and then want to re-raise it. But if there wasn’t any exception before, the raise statement raises a TypeError Exception.

    def somefunction():
        print("some cleaning")
    
    a=10
    b=0
    result=None
    
    try:
        result=a/b
        print(result)
    
    except Exception:            # Output ->
        somefunction()           # Some cleaning
        raise                    # Traceback (most recent call last):
                                 # File "python", line 8, in <module>
                                 # ZeroDivisionError: division by zero
    

    4. Raise exception (args) from original_exception

    This statement is used to create exception chaining in which an exception that is raised in response to another exception can contain the details of the original exception – as shown in the example below.

    class MyCustomException(Exception):
    pass
    
    a=10
    b=0
    reuslt=None
    try:
        try:
            result=a/b
    
        except ZeroDivisionError as exp:
            print("ZeroDivisionError -- ",exp)
            raise MyCustomException("Zero Division ") from exp
    
    except MyCustomException as exp:
            print("MyException",exp)
            print(exp.__cause__)
    

    Output:

    ZeroDivisionError --  division by zero
    MyException Zero Division
    division by zero
    

    2

    • 15

      Please note that PEP8 prefers exception(args) over exception (args)

      – Gloweye

      Jun 28, 2019 at 7:15

    • 10

      There is also raise exception(args) from None to say that the currently active exception was handled and is no longer of interest. Otherwise if you raise an exception inside an except block and it isn’t handled, tracebacks for both exceptions will be shown separated by the message “During handling of the above exception, another exception occurred”

      – cg909

      Apr 4, 2020 at 17:06