I have a try
/finally
clause in my script. Is it possible to get the exact error message from within the finally
clause?

- 32,208
- 39
- 178
- 361

- 2,759
- 9
- 30
- 36
5 Answers
No, at finally
time sys.exc_info
is all-None, whether there has been an exception
or not. Use:
try:
whatever
except:
here sys.exc_info is valid
to re-raise the exception, use a bare `raise`
else:
here you know there was no exception
finally:
and here you can do exception-independent finalization

- 854,459
- 170
- 1,222
- 1,395
-
Thanks. sys.exc_info (in an except clause) is what I need – Goutham Oct 23 '09 at 06:08
-
5As of Python 3.?, you can access `sys.exc_info` from within `finally:` block. – Kentzo Feb 01 '17 at 21:07
-
1@Kentzo I just tried that out in python 3.6. `sys.exc_info()` returns `(None, None, None)` in the finally block when you raised an exception. – Jonathan May 31 '17 at 17:36
-
6@Jonathan It's all None only if you handled the exception in one of the except's. – Kentzo Jun 01 '17 at 17:56
The finally
block will be executed regardless of whether an exception was thrown or not, so as Josh points out, you very likely don't want to be handling it there.
If you really do need the value of an exception that was raised, then you should catch the exception in an except
block, and either handle it appropriately or re-raise it, and then use that value in the finally block -- with the expectation that it may never have been set, if there was no exception raised during execution.
import sys
exception_name = exception_value = None
try:
# do stuff
except Exception as e:
exception_name, exception_value, _ = sys.exc_info()
raise # or don't -- it's up to you
finally:
# do something with exception_name and exception_value
# but remember that they might still be none

- 8,192
- 3
- 24
- 22

- 43,011
- 8
- 86
- 87
Actually, other answers are bit vague. So, let me clarify it. You can always invoke sys.exc_info() from finally block. However, its output will vary depending whether exception has been actually raised.
import sys
def f(i):
try:
if i == 1:
raise Exception
except Exception as e:
print "except -> " + str(sys.exc_info())
finally:
print "finally -> " + str(sys.exc_info())
f(0)
f(1)
>>>
finally -> (None, None, None)
except -> (<type 'exceptions.Exception'>, Exception(), <traceback object at 0x029438F0>)
finally -> (<type 'exceptions.Exception'>, Exception(), <traceback object at 0x029438F0>)
Thus, you can always know in finally block, whether exception was raised, if it's first level function. But sys.exc_info() will behave differently when length of call stack exceeds 1, as shown in below example. For more information, refer to How sys.exc_info() works?
import sys
def f(i):
try:
if i == 1:
raise Exception
except Exception as e:
print "except -> " + str(sys.exc_info())
finally:
print "finally -> " + str(sys.exc_info())
def f1(i):
if i == 0:
try:
raise Exception('abc')
except Exception as e:
pass
f(i)
f1(0)
f1(1)
>>>
finally -> (<type 'exceptions.Exception'>, Exception('abc',), <traceback object at 0x02A33940>)
except -> (<type 'exceptions.Exception'>, Exception(), <traceback object at 0x02A33990>)
finally -> (<type 'exceptions.Exception'>, Exception(), <traceback object at 0x02A33990>)
I hope, it makes things bit clearer.

- 1
- 1

- 10,806
- 4
- 68
- 97
-
3
-
-
4No, I execute the script on both python2 and python3. On python3 (after fixing minor syntactical issues), the output for `f(1)` is `finally -> (None, None, None)`, so you can not get the exception in the finally block that easy. – coldfix Jan 08 '18 at 10:12
No, at
finally
timesys.exc_info
is all-None, whether there has been an exception or not. Use [this instead]: …
The other answerer is correct in that you should be handling this inside the except
clause.
However, for posterity / the record, here is an answer to the original question as stated:
import sys
try:
int("not an integer LOL")
except:
e = sys.exc_info()[1]
# isinstance(e, ValueError) == True
raise # this line is optional; I have it commented for the example output
else:
e = None # you should do this to avoid a NameError
finally:
print("I really wanted to access %s inside of a finally clause. And I'm doing so now."
% repr(e))
This will print something like:
I really wanted to access
ValueError("invalid literal for int() with base 10: 'not an integer LOL'")
inside of a finally clause. And I'm doing so now.

- 658
- 7
- 19
You'll want to do that in the except clause, not the finally.
Refer to: http://www.doughellmann.com/articles/Python-Exception-Handling/

- 3,540
- 1
- 21
- 12
-
The question explicitly states the asker would like "to get the exact error message from within the finally clause". – Hugh W Jul 16 '20 at 10:57