I have a chunk of code like this
def f(x):
try:
g(x)
except Exception, e:
print "Exception %s: %d" % (x, e)
def h(x):
thread.start_new_thread(f, (x,))
Once in a while, I get this:
Unhandled exception in thread started by
Error in sys.excepthook:
Original exception was:
Unlike the code sample, that’s the complete text. I assume after the “by” there’s supposed to be a thread ID and after the colon there are supposed to be stack traces, but nope, nothing. I don’t know how to even start to debug this.
The error you’re seeing means the interpreter was exiting (because the main thread exited) while another thread was still executing Python code. Python will clean up its environment, cleaning out and throwing away all of the loaded modules (to make sure as many finalizers as possible execute) but unfortunately that means the still-running thread will start raising exceptions when it tries to use something that was already destroyed. And then that exception propagates up to the
start_new_threadfunction that started the thread, and it will try to report the exception — only to find that what it tries to use to report the exception is also gone, which causes the confusing empty error messages.In your specific example, this is all caused by your thread being started and your main thread exiting right away. Whether the newly started thread gets a chance to run before, during or after the interpreter exits (and thus whether you see it run as normal, run partially and report an error or never see it run) is entirely up to the OS thread scheduler.
If you’re using threads (which is not a bad thing to avoid) you probably want to not have threads running while you’re exiting the interpreter. The
threading.Threadclass is a better interface for starting new threads, and it will make the interpreter wait for all threads by default, on exit. If you really don’t want to wait for a thread to end, you can set its ‘daemonic’ flag in the Thread object to get the old behaviour — including the problem you see here.