How to re-raise an exception in nested try/except blocks?
As of Python 3 the traceback is stored in the exception, so a simple raise e
will do the (mostly) right thing:
try: something()except SomeError as e: try: plan_B() except AlsoFailsError: raise e # or raise e from None - see below
The traceback produced will include an additional notice that SomeError
occurred while handling AlsoFailsError
(because of raise e
being inside except AlsoFailsError
). This is misleading because what actually happened is the other way around - we encountered AlsoFailsError
, and handled it, while trying to recover from SomeError
. To obtain a traceback that doesn't include AlsoFailsError
, replace raise e
with raise e from None
.
In Python 2 you'd store the exception type, value, and traceback in local variables and use the three-argument form of raise
:
try: something()except SomeError: t, v, tb = sys.exc_info() try: plan_B() except AlsoFailsError: raise t, v, tb
Even if the accepted solution is right, it's good to point to the Six library which has a Python 2+3 solution, using six.reraise
.
six.reraise(exc_type, exc_value, exc_traceback=None)
Reraise an exception, possibly with a different traceback.[...]
So, you can write:
import sixtry: something()except SomeError: t, v, tb = sys.exc_info() try: plan_B() except AlsoFailsError: six.reraise(t, v, tb)
As per Drew McGowen's suggestion, but taking care of a general case (where a return value s
is present), here's an alternative to user4815162342's answer:
try: s = something()except SomeError as e: def wrapped_plan_B(): try: return False, plan_B() except: return True, None failed, s = wrapped_plan_B() if failed: raise