26

I am using Python 2.5 and trying to use a self-defined excepthook in my program. In the main thread it works perfectly fine. But in a thread started with the threading module the usual excepthook is called.

Here is an example showing the problem. Uncommenting the comment shows the desired behaviour.

import threading, sys

def myexcepthook(type, value, tb):
    print 'myexcepthook'

class A(threading.Thread, object):

    def __init__(self):
        threading.Thread.__init__(self, verbose=True)
#       raise Exception('in main')
        self.start()

    def run(self):
        print 'A'
        raise Exception('in thread')            

if __name__ == "__main__":
    sys.excepthook = myexcepthook
    A()

So, how can I use my own excepthook in a thread?

DavidRR
  • 18,291
  • 25
  • 109
  • 191
Sebastian
  • 261
  • 1
  • 3
  • 3

3 Answers3

26

I just stumbled over this problem and as it turns out, it was the right time to do so.

New in version 3.8: threading.excepthook

Handle uncaught exception raised by Thread.run().

The args argument has the following attributes:

exc_type: Exception type.
exc_value: Exception value, can be None.
exc_traceback: Exception traceback, can be None.
thread: Thread which raised the exception, can be None.

I don't know why, but be aware, that unlike sys.excepthook, threading.excepthook receives the arguments as a namedtuple instead of multiple arguments.

Community
  • 1
  • 1
johnson
  • 3,729
  • 3
  • 31
  • 32
  • 4
    This answer should be much higher rated now. Simple hack if you want exceptions outside of main thread to be handled as well set `threading.excepthook` as well along with `sys.excepthook` – Nilan Saha Aug 25 '21 at 23:17
23

It looks like this bug is still present in (at least) 3.4, and one of the workarounds in the discussion Nadia Alramli linked seems to work in Python 3.4 too.

For convenience and documentation sake, I'll post the code for (in my opinion) the best workaround here. I updated the coding style and comments slightly to make it more PEP8 and Pythonic.

import sys
import threading

def setup_thread_excepthook():
    """
    Workaround for `sys.excepthook` thread bug from:
    http://bugs.python.org/issue1230540

    Call once from the main thread before creating any threads.
    """

    init_original = threading.Thread.__init__

    def init(self, *args, **kwargs):

        init_original(self, *args, **kwargs)
        run_original = self.run

        def run_with_except_hook(*args2, **kwargs2):
            try:
                run_original(*args2, **kwargs2)
            except Exception:
                sys.excepthook(*sys.exc_info())

        self.run = run_with_except_hook

    threading.Thread.__init__ = init
gitaarik
  • 42,736
  • 12
  • 98
  • 105
  • I wish this were the accepted answer. Looks like there never was one. Feel free to put it over at https://stackoverflow.com/questions/49663124/cause-python-to-exit-if-any-thread-has-an-exception and I'd mark it as the answer. – Travis Griggs Apr 10 '18 at 17:55
  • 1
    @TravisGriggs Stack Overflow won't like this as they don't like duplicate content. You can answer your own question referencing this question though, and accept that as the answer. – gitaarik Apr 11 '18 at 11:04
  • 3
    The bug is fixed as of python 3.8. – max Feb 19 '20 at 05:47
13

It looks like there is a related bug reported here with workarounds. The suggested hacks basically wrap run in a try/catch and then call sys.excepthook(*sys.exc_info())

Nadia Alramli
  • 111,714
  • 37
  • 173
  • 152