It's a well-known (or perhaps just "known" :) ) issue with gevent:
try:
1/0
except:
# here the traceback is available: raise would work as expected
gevent.sleep(0)
# here the traceback is gone: raise would work and do raise ZeroDivisionError but the original stacktrace is lost
I can only suggest a work around: either print the stacktrace immediately or save it in text form for later.
I've done some digging, and managed to figure out what's happening. Specifically, it seems as if under some condition that gevent deliberately clears the traceback information. Specifically, this commit from way back in 2010:
I've confirmed that this is what's happening by commenting out the lines to exc_clear() and core.set_exc_info in my local version of hub.py, and the traceback is preserved.
You now have exc_info() raised in one greenlet accessible by all other greenlets (and they are able to override it too). Much worse bug.
Is there any way around this? It would be great if someone could shed more light on why this is being done, it's not clear to me why you'd deliberately throw away traceback objects? I assume perhaps a memory leak issue?
Yes, there were indeed a problem (leak) when trying to save/restore the traceback part of exc_info like we do with exc_type and exc_value. I'm not sure if was just a bug or fundamental issue of how greenlet interacts with PyThreadState. If someone wants to look at it, any insight into what's going on would much appreciated.
eventlet seemingly does not have it because it completely ignores the fact that all greenlets share PyThreadState (and thus exc_info()) and leaks sys.exc_info() into unrelated contexts.