Python print error message and traceback in except (tested)
Printing a caught exception with print(e) often loses the type, the line and even the message. We measured what str, repr, traceback and logging each print on Python 3.13.5.
1. print(e) can print almost nothing
errors = [KeyError("user_id"), FileNotFoundError(2, "No such file or directory", "x.csv"),
ValueError(), TimeoutError()]
for e in errors:
print(f"print(e): {str(e)!r:45} repr(e): {e!r}")
Output:
print(e): "'user_id'" repr(e): KeyError('user_id')
print(e): "[Errno 2] No such file or directory: 'x.csv'" repr(e): FileNotFoundError(2, 'No such file or directory')
print(e): '' repr(e): ValueError()
print(e): '' repr(e): TimeoutError()
Measured on Python 3.13.5: print(e) prints only the message, and the message is often useless on its own: a KeyError prints just the quoted key, and exceptions raised without arguments print an empty string. repr(e) adds the type but, for a FileNotFoundError, drops the filename that str(e) shows. Print both the type and the message: f"{type(e).__name__}: {e}".
2. The line number and the full traceback as a string
import traceback
def load(config):
return config["user_id"]
try:
load({})
except Exception as e:
print(f"{type(e).__name__}: {e}") # type + message
tb = e.__traceback__
while tb.tb_next: # walk to the innermost frame
tb = tb.tb_next
print("failed at line", tb.tb_lineno, "in", tb.tb_frame.f_code.co_name)
print("---- traceback.format_exc() ----")
print(traceback.format_exc(), end="")
Output:
KeyError: 'user_id'
failed at line 4 in load
---- traceback.format_exc() ----
Traceback (most recent call last):
File "/tmp/pe/b2.py", line 7, in <module>
load({})
~~~~^^^^
File "/tmp/pe/b2.py", line 4, in load
return config["user_id"]
~~~~~~^^^^^^^^^^^
KeyError: 'user_id'
Measured: e.__traceback__ starts at the frame that caught the exception; walk tb_next to the end to get the line that actually raised it (line 4, inside load). traceback.format_exc() returns the same text Python would print for an uncaught error, as a string you can save or send.
3. logging.exception: message plus traceback
import logging, sys
logging.basicConfig(stream=sys.stdout, format="%(levelname)s %(message)s")
try:
1 / 0
except ZeroDivisionError:
logging.exception("computing ratio failed") # message + full traceback
print("program continues")
Output:
ERROR computing ratio failed
Traceback (most recent call last):
File "/tmp/pe/b3.py", line 4, in <module>
1 / 0
~~^~~
ZeroDivisionError: division by zero
program continues
Measured: called inside an except block, logging.exception() logs at ERROR level and appends the full traceback, and the program keeps running. This is usually what you want in a long-running script. If your log message doesn't appear at all, see our logging not printing guide.
4. print(e) hides the original cause
import traceback
try:
try:
int("abc")
except ValueError as e:
raise RuntimeError("bad config value") from e
except RuntimeError as e:
print("print(e) only shows:", e)
print("---- traceback.print_exc() ----")
traceback.print_exc()
Output:
print(e) only shows: bad config value
---- traceback.print_exc() ----
Traceback (most recent call last):
File "/tmp/pe/b4.py", line 4, in <module>
int("abc")
~~~^^^^^^^
ValueError: invalid literal for int() with base 10: 'abc'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/tmp/pe/b4.py", line 6, in <module>
raise RuntimeError("bad config value") from e
RuntimeError: bad config value
Measured: with raise ... from e, print(e) shows only the outer message, while traceback.print_exc() prints both exceptions and the line that started it. Note that print_exc() writes to stderr, not stdout (pass file=sys.stdout to change that).
Frequently asked questions
How do I print the error message of an exception in Python?
print(f'{type(e).__name__}: {e}'). We measured print(e) alone printing only the quoted key for a KeyError and an empty string for ValueError() on Python 3.13.5.
How do I print the full traceback in an except block?
traceback.print_exc() prints it, traceback.format_exc() returns it as a string, and logging.exception() logs it. We measured all three.
How do I get the line number where the exception happened?
Walk e.__traceback__ through tb_next to the last frame and read tb_lineno. We measured it returning the line inside the called function, not the caller.
Why does print(e) not show the original error?
With raise ... from e, str() is only the new exception's message. We measured traceback.print_exc() showing both exceptions.
Written with AI assistance. Measured on 2026-10-09 with Python 3.13.5: str() and repr() of four exceptions, the traceback line number and format_exc(), logging.exception(), and a chained exception with print_exc(). Every block was run verbatim and its output pasted from that run. PlainHeaders is our extension; everything else here is built-in Python.