358

some_function() raises an exception while executing, so the program jumps to the except:

try:
    some_function()
except:
    print("exception happened!")

How do I see what caused the exception to occur?

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
Shang Wang
  • 24,909
  • 20
  • 73
  • 94
  • 11
    Never ever ever use bare `except:` (without a bare `raise`), except *maybe* once per program, and preferably not then. – Mike Graham Mar 22 '12 at 14:18
  • If you use multiple `except` clauses you wont need to check the exception type, that is what is usually done to act accordingly to a specific exception type. – Rik Poggi Mar 22 '12 at 14:29
  • 3
    If you care about the type of exception, it's because you've already considered what types of exception might logically occur. – Karl Knechtel Mar 22 '12 at 14:48
  • 7
    Inside `except` block the exception is available through [`sys.exc_info()`](https://docs.python.org/2/library/sys.html#sys.exc_info) function – *This function returns a tuple of three values that give information about the exception that is currently being handled.* – Piotr Dobrogost Dec 20 '17 at 11:04
  • Related: [How to print an error in Python?](https://stackoverflow.com/q/1483429/3357935) – Stevoisiak Jun 01 '18 at 15:27
  • how do I fill in the blank here? `except __ as e` . That is, how do I get the class/type in order to catch it? I'm using databricks btw so this is what I see when I try and print `type(e)`: .f_with_exception_handling..ExecutionError'> – information_interchange Jul 03 '19 at 20:11

16 Answers16

576

The other answers all point out that you should not catch generic exceptions, but no one seems to want to tell you why, which is essential to understanding when you can break the "rule". Here is an explanation. Basically, it's so that you don't hide:

So as long as you take care to do none of those things, it's OK to catch the generic exception. For instance, you could provide information about the exception to the user another way, like:

  • Present exceptions as dialogs in a GUI
  • Transfer exceptions from a worker thread or process to the controlling thread or process in a multithreading or multiprocessing application

So how to catch the generic exception? There are several ways. If you just want the exception object, do it like this:

try:
    someFunction()
except Exception as ex:
    template = "An exception of type {0} occurred. Arguments:\n{1!r}"
    message = template.format(type(ex).__name__, ex.args)
    print message

Make sure message is brought to the attention of the user in a hard-to-miss way! Printing it, as shown above, may not be enough if the message is buried in lots of other messages. Failing to get the users attention is tantamount to swallowing all exceptions, and if there's one impression you should have come away with after reading the answers on this page, it's that this is not a good thing. Ending the except block with a raise statement will remedy the problem by transparently reraising the exception that was caught.

The difference between the above and using just except: without any argument is twofold:

  • A bare except: doesn't give you the exception object to inspect
  • The exceptions SystemExit, KeyboardInterrupt and GeneratorExit aren't caught by the above code, which is generally what you want. See the exception hierarchy.

If you also want the same stacktrace you get if you do not catch the exception, you can get that like this (still inside the except clause):

import traceback
print traceback.format_exc()

If you use the logging module, you can print the exception to the log (along with a message) like this:

import logging
log = logging.getLogger()
log.exception("Message for you, sir!")

If you want to dig deeper and examine the stack, look at variables etc., use the post_mortem function of the pdb module inside the except block:

import pdb
pdb.post_mortem()

I've found this last method to be invaluable when hunting down bugs.

Community
  • 1
  • 1
Lauritz V. Thaulow
  • 49,139
  • 12
  • 73
  • 92
  • 2
    traceback.print_exc() would do the same thing as your more complicated "".join-thing, I think. – Gurgeh Mar 22 '12 at 14:16
  • 2
    @Gurgeh Yes, but I do not know if he wants to print it or save it to a file or log it or do something else with it. – Lauritz V. Thaulow Mar 22 '12 at 14:19
  • I didn't downvoted, but I'd say that's because you should have put a huge fat worning at the beginning saying **You shouldn't need any of this, but here's how it could be done**. And maybe because you suggest to catch the generic Exception. – Rik Poggi Mar 22 '12 at 14:57
  • 15
    @Rik I think you may very well need _all_ of this. For instance, if you have a program with a GUI and a backend, and you want to present all exceptions from the backend as GUI messages instead of having your program quit with a stack trace. In such a case, you should catch the _generic_ Exception, create a traceback text for the dialog, log the exception too, and if in debug mode, enter post-mortem. – Lauritz V. Thaulow Mar 22 '12 at 19:17
  • 26
    @RikPoggi: Naive thinking. There are many reasonable circumstances when you need to catch exceptions from someone else's code and you don't know what exceptions will be raised. – stackoverflowuser2010 Oct 01 '16 at 00:37
  • 1
    This postmortem trick helped me narrow down an exception type of `objc.error` which is sort of a wonky one. – jxramos Feb 21 '19 at 23:22
155

Get the name of the class that exception object belongs:

e.__class__.__name__

and using print_exc() function will also print stack trace which is essential info for any error message.

Like this:

from traceback import print_exc

class CustomException(Exception): pass

try:
    raise CustomException("hi")
except Exception as e:
    print ('type is:', e.__class__.__name__)
    print_exc()
    # print("exception happened!")

You will get output like this:

type is: CustomException
Traceback (most recent call last):
  File "exc.py", line 7, in <module>
    raise CustomException("hi")
CustomException: hi

And after print and analysis, the code can decide not to handle exception and just execute raise:

from traceback import print_exc

class CustomException(Exception): pass

def calculate():
    raise CustomException("hi")

try:
    calculate()
except CustomException as e:
    # here do some extra steps in case of CustomException
    print('custom logic doing cleanup and more')
    # then re raise same exception
    raise

Output:

custom logic doing cleanup and more

And interpreter prints exception:

Traceback (most recent call last):
  File "test.py", line 9, in <module>
    calculate()
  File "test.py", line 6, in calculate
    raise CustomException("hi")
__main__.CustomException: hi

After raise original exception continues to propagate further up the call stack. (Beware of possible pitfall) If you raise new exception it caries new (shorter) stack trace.

from traceback import print_exc

class CustomException(Exception):
    def __init__(self, ok):
        self.ok = ok

def calculate():
    raise CustomException(False)

try:
    calculate()
except CustomException as e:
    if not e.ok:
        # Always use `raise` to rethrow exception
        # following is usually mistake, but here we want to stress this point
        raise CustomException(e.ok)
    print("handling exception")

Output:

Traceback (most recent call last):
  File "test.py", line 13, in <module>
    raise CustomException(e.message)
__main__.CustomException: hi    

Notice how traceback does not include calculate() function from line 9 which is the origin of original exception e.

Alex
  • 2,837
  • 5
  • 25
  • 27
  • If you want to store the traceback as a string, you can use `traceback.format_exc()` as well – Stevoisiak Jun 01 '18 at 15:18
  • 1
    `e.__class__.__name__` is this the same as `type(e).__name__`, as suggested by the answer above? – information_interchange Jul 03 '19 at 20:05
  • 1
    @information_interchange yes. The question and accepted answer content changed completely over time. It is shame other participants are not notified by SO machinery :( – Alex Jul 08 '19 at 12:39
  • thanks, that error chaining was new to me! Very useful for injecting a new message to HTTP errors. – CHURLZ Aug 07 '20 at 08:54
  • Please use `except CustomException` directly and don't check type afterwards. – DSchmidt Nov 20 '21 at 13:05
  • @DSchmidt "Don't do it" is not great answer to any question, please see how question is formulated. – Alex Nov 20 '21 at 17:28
  • @Alex I'm not answering any questions. I'm just commenting on the current state of this answer. Which uses `if e.__class__ == CustomException` instead of the much cleaner `except CustomException`. – DSchmidt Nov 22 '21 at 18:06
  • @DSchmidt the question is: "what *type* of exception occurred?" this is the crux of the answer. If you use `except CustomException` there is no question what *type* of exception is it, because its hardcoded. The `.__class__` is what one learns from this answer. – Alex Nov 22 '21 at 18:41
  • @Alex and your first example answers that question reasonably well. Your other examples showing the raise and logging differences should showcase the correct `except` IMHO. People copy this. – DSchmidt Nov 22 '21 at 19:24
  • @DSchmidt you are on point – Alex Nov 22 '21 at 20:06
16

You usually should not catch all possible exceptions with try: ... except as this is overly broad. Just catch those that are expected to happen for whatever reason. If you really must, for example if you want to find out more about some problem while debugging, you should do

try:
    ...
except Exception as ex:
    print ex # do whatever you want for debugging.
    raise    # re-raise exception.
hochl
  • 12,524
  • 10
  • 53
  • 87
  • 22
    The use of the word "never" here has never been so wrong. I use `try: ... except Exception:` around lots of things, e.g. usage of network dependent libraries, or a data masseuse that may get weird stuff sent to her. Naturally I have proper logging too. This is crucial to allow the program to continue operating in the case of a single mistake in input data. – thnee Jul 03 '13 at 15:37
  • 4
    Ever tried to catch all the exceptions that could be raised when sending a email using `smtplib`? – linusg Jun 28 '16 at 19:16
  • 2
    There may be some special cases where catching all exceptions is necessary, but on a general level you should just catch what you expect so you don't accidentally hide errors that you did not anticipate. Good logging is a good idea, too, of course. – hochl Jun 29 '16 at 08:28
  • 5
    It is perfectly reasonable to catch all exceptions. If you are calling a third-party library, you may not know what exceptions will be raised in that library. In such a case, the only recourse is to catch all the exceptions, for example to log them in a file. – stackoverflowuser2010 Oct 01 '16 at 00:33
  • Ok ok you're right, I'll rephrase my answer to make clear that there are valid use cases for a catch all. – hochl Oct 08 '16 at 15:17
  • Why is the re-raising necessary? To crash the program deliberately? – aderchox Mar 31 '20 at 14:10
  • Because re-raising it will not hide the exception, you just want to print it out for debugging purposes before you continue the program unchanged. – hochl Apr 02 '20 at 15:59
13

Most answers point to except (…) as (…): syntax (rightly so) but at the same time nobody wants to talk about an elephant in the room, where the elephant is sys.exc_info() function. From the documentation of sys module (emphasis mine):

This function returns a tuple of three values that give information about the exception that is currently being handled.
(…)
If no exception is being handled anywhere on the stack, a tuple containing three None values is returned. Otherwise, the values returned are (type, value, traceback). Their meaning is: type gets the type of the exception being handled (a subclass of BaseException); value gets the exception instance (an instance of the exception type); traceback gets a traceback object (see the Reference Manual) which encapsulates the call stack at the point where the exception originally occurred.

I think the sys.exc_info() could be treated as the most direct answer to the original question of How do I know what type of exception occurred?

Piotr Dobrogost
  • 41,292
  • 40
  • 236
  • 366
  • 2
    That's the correct answer to me as it does solve the problem of what exception is occurring so what should I put instead of bare `except`. Just for the sake of completeness, `exctype, value = sys.exc_info()[:2]` will tell you the exception type which can then be used on the `except`. – Ondrej Burkert May 03 '18 at 14:10
10

These answers are fine for debugging, but for programmatically testing the exception, isinstance(e, SomeException) can be handy, as it tests for subclasses of SomeException too, so you can create functionality that applies to hierarchies of exceptions.

Chris
  • 5,664
  • 6
  • 44
  • 55
8

Unless somefunction is a very bad coded legacy function, you shouldn't need what you're asking.

Use multiple except clause to handle in different ways different exceptions:

try:
    someFunction()
except ValueError:
    # do something
except ZeroDivision:
    # do something else

The main point is that you shouldn't catch generic exception, but only the ones that you need to. I'm sure that you don't want to shadow unexpected errors or bugs.

Rik Poggi
  • 28,332
  • 6
  • 65
  • 82
  • 13
    If you are using a third-party library, you may not know what exceptions will be raised inside of it. How can you possibly catch all of them individually? – stackoverflowuser2010 Oct 01 '16 at 00:34
7

In Python 2, the following are useful

except Exception, exc:

    # This is how you get the type
    excType = exc.__class__.__name__

    # Here we are printing out information about the Exception
    print 'exception type', excType
    print 'exception msg', str(exc)

    # It's easy to reraise an exception with more information added to it
    msg = 'there was a problem with someFunction'
    raise Exception(msg + 'because of %s: %s' % (excType, exc))
hostingutilities.com
  • 8,894
  • 3
  • 41
  • 51
4

Use type class and as statement

try:#code
except Exception as e:
     m=type(e)
     #m is the class of the exception
     strm=str(m)
     #strm is the string of m
Supergamer
  • 411
  • 4
  • 13
3

Hope this will help a little more

import sys
varExcepHandling, varExcepHandlingZer = 2, 0
try:
  print(varExcepHandling/varExcepHandlingZer)
except Exception as ex: 
  print(sys.exc_info())

'sys.exc_info()' will return a tuple, if you only want the exception class name use 'sys.exc_info()[0]'

Note:- if you want to see all the exception classes just write dir(__builtin__)

Anurag Bhakuni
  • 2,379
  • 26
  • 32
1

Here's how I'm handling my exceptions. The idea is to do try solving the issue if that's easy, and later add a more desirable solution if possible. Don't solve the issue in the code that generates the exception, or that code loses track of the original algorithm, which should be written to-the-point. However, pass what data is needed to solve the issue, and return a lambda just in case you can't solve the problem outside of the code that generates it.

path = 'app.p'

def load():
    if os.path.exists(path):
        try:
            with open(path, 'rb') as file:
                data = file.read()
                inst = pickle.load(data)
        except Exception as e:
            inst = solve(e, 'load app data', easy=lambda: App(), path=path)()
    else:
        inst = App()
    inst.loadWidgets()

# e.g. A solver could search for app data if desc='load app data'
def solve(e, during, easy, **kwargs):
    class_name = e.__class__.__name__
    print(class_name + ': ' + str(e))
    print('\t during: ' + during)
    return easy

For now, since I don't want to think tangentially to my app's purpose, I haven't added any complicated solutions. But in the future, when I know more about possible solutions (since the app is designed more), I could add in a dictionary of solutions indexed by during.

In the example shown, one solution might be to look for app data stored somewhere else, say if the 'app.p' file got deleted by mistake.

For now, since writing the exception handler is not a smart idea (we don't know the best ways to solve it yet, because the app design will evolve), we simply return the easy fix which is to act like we're running the app for the first time (in this case).

MathCrackExchange
  • 595
  • 1
  • 6
  • 25
0

To add to Lauritz's answer, I created a decorator/wrapper for exception handling and the wrapper logs which type of exception occurred.

class general_function_handler(object):
    def __init__(self, func):
        self.func = func
    def __get__(self, obj, type=None):
        return self.__class__(self.func.__get__(obj, type))
    def __call__(self, *args, **kwargs):
        try:
            retval = self.func(*args, **kwargs)
        except Exception, e :
            logging.warning('Exception in %s' % self.func)
            template = "An exception of type {0} occured. Arguments:\n{1!r}"
            message = template.format(type(e).__name__, e.args)
            logging.exception(message)
            sys.exit(1) # exit on all exceptions for now
        return retval

This can be called on a class method or a standalone function with the decorator:

@general_function_handler

See my blog about for the full example: http://ryaneirwin.wordpress.com/2014/05/31/python-decorators-and-exception-handling/

rirwin
  • 199
  • 2
  • 4
-1

You can start as Lauritz recommended, with:

except Exception as ex:

and then just to print ex like so:

try:
    #your try code here
except Exception as ex:
    print ex
icedwater
  • 4,701
  • 3
  • 35
  • 50
Gura
  • 11
  • 7
  • Can you elaborate a bit so your answer stands alone? – GHC Mar 24 '15 at 14:32
  • 1
    sure: you can print the caught exception like this: try: #your try code here except Exception as ex: print ex now the error will be printed – Gura Mar 24 '15 at 15:28
-2

Your question is: "How can I see exactly what happened in the someFunction() that caused the exception to happen?"

It seems to me that you are not asking about how to handle unforeseen exceptions in production code (as many answers assumed), but how to find out what is causing a particular exception during development.

The easiest way is to use a debugger that can stop where the uncaught exception occurs, preferably not exiting, so that you can inspect the variables. For example, PyDev in the Eclipse open source IDE can do that. To enable that in Eclipse, open the Debug perspective, select Manage Python Exception Breakpoints in the Run menu, and check Suspend on uncaught exceptions.

-3

Use the below for both Exception type and Exception text

import sys
print(str(sys.exc_info()[0]).split(' ')[1].strip('>').strip("'")+"-"+(str(sys.exc_info()[1])))

if you want only exception type: Use -->

import sys
print(str(sys.exc_info()[0]).split(' ')[1].strip('>').strip("'"))

Thanks Rajeshwar
curious_nustian
  • 596
  • 2
  • 7
  • 22
-3

The actual exception can be captured in the following way:

try:
    i = 1/0
except Exception as e:
    print e

You can learn more about exceptions from The Python Tutorial.

Kevin Coffey
  • 386
  • 1
  • 6
-4

Just refrain from catching the exception and the traceback that Python prints will tell you what exception occurred.

Mike Graham
  • 73,987
  • 14
  • 101
  • 130