The answer to this question depends on the version of Python you're using.

In Python 3

It's simple: exceptions come equipped with a __traceback__ attribute that contains the traceback. This attribute is also writable, and can be conveniently set using the with_traceback method of exceptions:

raise Exception("foo occurred").with_traceback(tracebackobj)

These features are minimally described as part of the raise documentation.

All credit for this part of the answer should go to Vyctor, who first posted this information. I'm including it here only because this answer is stuck at the top, and Python 3 is becoming more common.

In Python 2

It's annoyingly complex. The trouble with tracebacks is that they have references to stack frames, and stack frames have references to the tracebacks that have references to stack frames that have references to... you get the idea. This causes problems for the garbage collector. (Thanks to ecatmur for first pointing this out.)

The nice way of solving this would be to surgically break the cycle after leaving the except clause, which is what Python 3 does. The Python 2 solution is much uglier: you are provided with an ad-hoc function,sys.exc_info(), which only works inside the except clause. It returns a tuple containing the exception, the exception type, and the traceback for whatever exception is currently being handled.

So if you are inside the except clause, you can use the output of sys.exc_info() along with the traceback module to do various useful things:

>>> import sys, traceback
>>> def raise_exception():
...     try:
...         raise Exception
...     except Exception:
...         ex_type, ex, tb = sys.exc_info()
...         traceback.print_tb(tb)
...     finally:
...         del tb
... 
>>> raise_exception()
  File "<stdin>", line 3, in raise_exception

But as your edit indicates, you're trying to get the traceback that would have been printed if your exception had not been handled, after it has already been handled. That's a much harder question. Unfortunately, sys.exc_info returns (None, None, None) when no exception is being handled. Other related sys attributes don't help either. sys.exc_traceback is deprecated and undefined when no exception is being handled; sys.last_traceback seems perfect, but it appears only to be defined during interactive sessions.

If you can control how the exception is raised, you might be able to use inspect and a custom exception to store some of the information. But I'm not entirely sure how that would work.

To tell the truth, catching and returning an exception is kind of an unusual thing to do. This might be a sign that you need to refactor anyway.

Answer from senderle on Stack Overflow
Top answer
1 of 7
137

The answer to this question depends on the version of Python you're using.

In Python 3

It's simple: exceptions come equipped with a __traceback__ attribute that contains the traceback. This attribute is also writable, and can be conveniently set using the with_traceback method of exceptions:

raise Exception("foo occurred").with_traceback(tracebackobj)

These features are minimally described as part of the raise documentation.

All credit for this part of the answer should go to Vyctor, who first posted this information. I'm including it here only because this answer is stuck at the top, and Python 3 is becoming more common.

In Python 2

It's annoyingly complex. The trouble with tracebacks is that they have references to stack frames, and stack frames have references to the tracebacks that have references to stack frames that have references to... you get the idea. This causes problems for the garbage collector. (Thanks to ecatmur for first pointing this out.)

The nice way of solving this would be to surgically break the cycle after leaving the except clause, which is what Python 3 does. The Python 2 solution is much uglier: you are provided with an ad-hoc function,sys.exc_info(), which only works inside the except clause. It returns a tuple containing the exception, the exception type, and the traceback for whatever exception is currently being handled.

So if you are inside the except clause, you can use the output of sys.exc_info() along with the traceback module to do various useful things:

>>> import sys, traceback
>>> def raise_exception():
...     try:
...         raise Exception
...     except Exception:
...         ex_type, ex, tb = sys.exc_info()
...         traceback.print_tb(tb)
...     finally:
...         del tb
... 
>>> raise_exception()
  File "<stdin>", line 3, in raise_exception

But as your edit indicates, you're trying to get the traceback that would have been printed if your exception had not been handled, after it has already been handled. That's a much harder question. Unfortunately, sys.exc_info returns (None, None, None) when no exception is being handled. Other related sys attributes don't help either. sys.exc_traceback is deprecated and undefined when no exception is being handled; sys.last_traceback seems perfect, but it appears only to be defined during interactive sessions.

If you can control how the exception is raised, you might be able to use inspect and a custom exception to store some of the information. But I'm not entirely sure how that would work.

To tell the truth, catching and returning an exception is kind of an unusual thing to do. This might be a sign that you need to refactor anyway.

2 of 7
116

Since Python 3.0[PEP 3109] the built in class Exception has a __traceback__ attribute which contains a traceback object (with Python 3.2.3):

>>> try:
...     raise Exception()
... except Exception as e:
...     tb = e.__traceback__
...
>>> tb
<traceback object at 0x00000000022A9208>

The problem is that after Googling __traceback__ for a while I found only few articles but none of them describes whether or why you should (not) use __traceback__.

However, the Python 3 documentation for raise says that:

A traceback object is normally created automatically when an exception is raised and attached to it as the __traceback__ attribute, which is writable.

So I assume it's meant to be used.

🌐
Python
docs.python.org › 3 › library › traceback.html
traceback — Print or retrieve a stack traceback
The optional limit argument has the same meaning as for print_tb(). If chain is true (the default), then chained exceptions (the __cause__ or __context__ attributes of the exception) will be printed as well, like the interpreter itself does when printing an unhandled exception. Changed in version 3.5: The etype argument is ignored and inferred from the type of value. Changed in version 3.10: The etype parameter has been renamed to exc and is now positional-only. traceback.print_exc(limit=None, file=None, chain=True)¶
🌐
Real Python
realpython.com › python-traceback
Understanding the Python Traceback – Real Python
July 29, 2019 - The Python documentation defines when this exception is raised: Raised when the import statement has troubles trying to load a module. Also raised when the ‘from list’ in from ... import has a name that cannot be found. (Source) Here’s an example of the ImportError and ModuleNotFoundError being raised: ... >>> import asdf Traceback (most recent call last): File "<stdin>", line 1, in <module> ModuleNotFoundError: No module named 'asdf' >>> from collections import asdf Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: cannot import name 'asdf'
🌐
Python Module of the Week
pymotw.com › 2 › traceback
traceback – Extract, format, and print exceptions and stack traces. - Python Module of the Week
The functions in traceback fall into several common categories. There are functions for extracting raw tracebacks from the current runtime environment (either an exception handler for a traceback, or the regular stack).
🌐
GeeksforGeeks
geeksforgeeks.org › python › how-to-print-exception-stack-trace-in-python
How to Print Exception Stack Trace in Python - GeeksforGeeks
July 15, 2025 - Traceback (most recent call last): ... a try block, which raises a ZeroDivisionError. The except block catches the exception and prints the detailed error traceback using traceback.print_exc(), helping in debugging by displaying ...
Top answer
1 of 16
1534

traceback.format_exc() will yield more info if that's what you want.

import traceback

def do_stuff():
    raise Exception("test exception")

try:
    do_stuff()
except Exception:
    print(traceback.format_exc())

This outputs:

Traceback (most recent call last):
  File "main.py", line 9, in <module>
    do_stuff()
  File "main.py", line 5, in do_stuff
    raise Exception("test exception")
Exception: test exception
2 of 16
880

Some other answer have already pointed out the traceback module.

Please notice that with print_exc, in some corner cases, you will not obtain what you would expect. In Python 2.x:

import traceback

try:
    raise TypeError("Oups!")
except Exception, err:
    try:
        raise TypeError("Again !?!")
    except:
        pass

    traceback.print_exc()

...will display the traceback of the last exception:

Traceback (most recent call last):
  File "e.py", line 7, in <module>
    raise TypeError("Again !?!")
TypeError: Again !?!

If you really need to access the original traceback one solution is to cache the exception infos as returned from exc_info in a local variable and display it using print_exception:

import traceback
import sys

try:
    raise TypeError("Oups!")
except Exception, err:
    try:
        exc_info = sys.exc_info()

        # do you usefull stuff here
        # (potentially raising an exception)
        try:
            raise TypeError("Again !?!")
        except:
            pass
        # end of useful stuff


    finally:
        # Display the *original* exception
        traceback.print_exception(*exc_info)
        del exc_info

Producing:

Traceback (most recent call last):
  File "t.py", line 6, in <module>
    raise TypeError("Oups!")
TypeError: Oups!

Few pitfalls with this though:

  • From the doc of sys_info:

    Assigning the traceback return value to a local variable in a function that is handling an exception will cause a circular reference. This will prevent anything referenced by a local variable in the same function or by the traceback from being garbage collected. [...] If you do need the traceback, make sure to delete it after use (best done with a try ... finally statement)

  • but, from the same doc:

    Beginning with Python 2.2, such cycles are automatically reclaimed when garbage collection is enabled and they become unreachable, but it remains more efficient to avoid creating cycles.


On the other hand, by allowing you to access the traceback associated with an exception, Python 3 produce a less surprising result:

import traceback

try:
    raise TypeError("Oups!")
except Exception as err:
    try:
        raise TypeError("Again !?!")
    except:
        pass

    traceback.print_tb(err.__traceback__)

... will display:

  File "e3.py", line 4, in <module>
    raise TypeError("Oups!")
🌐
Coursera
coursera.org › tutorials › how to print, read, and format a python traceback
How to Print, Read, and Format a Python Traceback | Coursera
March 10, 2023 - Tracebacks are read from the bottom up. The exception or error encountered is always on the last line of the traceback. Formatting a traceback can provide you with additional information for troubleshooting the error you’ve encountered.
🌐
Real Python
realpython.com › ref › stdlib › traceback
traceback | Python Standard Library – Real Python
>>> import traceback >>> try: ... {"a": 1}["b"] ... except KeyError: ... traceback.print_exc() Traceback (most recent call last): ... KeyError: 'b' ... Colorizes traceback output by default in Python 3.13 and later, configurable through the PYTHON_COLORS and NO_COLOR environment variables
Find elsewhere
Top answer
1 of 12
914

See the traceback module, specifically the format_exc() function. Here.

import traceback

try:
    raise ValueError
except ValueError:
    tb = traceback.format_exc()
else:
    tb = "No error"
finally:
    print(tb)
2 of 12
130

Let's create a decently complicated stacktrace, in order to demonstrate that we get the full stacktrace:

def raise_error():
    raise RuntimeError('something bad happened!')

def do_something_that_might_error():
    raise_error()

Logging the full stacktrace

A best practice is to have a logger set up for your module. It will know the name of the module and be able to change levels (among other attributes, such as handlers)

import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

And we can use this logger to get the error:

try:
    do_something_that_might_error()
except Exception as error:
    logger.exception(error)

Which logs:

ERROR:__main__:something bad happened!
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

And so we get the same output as when we have an error:

>>> do_something_that_might_error()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

Getting just the string

If you really just want the string, use the traceback.format_exc function instead, demonstrating logging the string here:

import traceback
try:
    do_something_that_might_error()
except Exception as error:
    just_the_string = traceback.format_exc()
    logger.debug(just_the_string)

Which logs:

DEBUG:__main__:Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!
🌐
Sentry
sentry.io › sentry answers › python › print stack traces in python
Print stack traces in Python | Sentry
July 3, 2026 - If we just want the stack trace ... using Python’s built-in inspect module to iterate through each frame of the exception’s traceback object. For example: import inspect def print_stacktrace(exception): stacktrace = exception.__traceback__ for frame in inspect.getinnerframes(stacktrace): ...
🌐
GeeksforGeeks
geeksforgeeks.org › traceback-in-python
Traceback in Python - GeeksforGeeks
August 1, 2020 - Traceback for most recent call Location of the program Line in the program where error was encountered Name of the error: relevant information about the exception Example : Traceback (most recent call last): File "C:/Python27/hdg.py", line 5, in value = A[5] IndexError: list index out of range The module uses traceback objects, this is the object type that is stored in the sys.last_traceback variable and returned as the third item from sys.exc_info().
🌐
Coderz Column
coderzcolumn.com › tutorials › python › traceback-how-to-extract-format-and-print-error-stack-traces-in-python
traceback - How to Extract, Format, and Print Error Stack Traces in Python by Sunny Solanki
January 14, 2021 - Below we have explained how we can generate StackSummary instance from the frame generator generated by walk_tb() method. We have then formatted stack trace as well using the StackSummary instance. import traceback import random import sys try: out = random.randint(-5,-10) except Exception as e: tbk = e.__traceback__ print("\n==================Traceback 1 ===================\n") for frame in traceback.walk_tb(tbk): print(frame) print("\n==================Traceback 2 ===================\n") stack_summary = traceback.StackSummary.extract(traceback.walk_tb(tbk)) print("Ps | s | %5s | s" %("File Name", "Method Name", "Line Number", "Line")) print("-"*100) for frame_summary in stack_summary: print("Ps | s | d | s"%(frame_summary.filename, frame_summary.name, frame_summary.lineno, frame_summary.line)) print("-"*100)
🌐
Python Module of the Week
pymotw.com › 3 › traceback › index.html
traceback — Exceptions and Stack Traces
Each entry is a tuple with four parts: the name of the source file, the line number in that file, the name of the function, and the source text from that line with whitespace stripped (if the source is available). $ python3 traceback_extract_tb.py format_exception(): traceback_extract_tb.py:18:<module>: produce_exception() traceback_example.py :17:produce_exception(): produce_exception(recursion_level - 1) traceback_example.py :17:produce_exception(): produce_exception(recursion_level - 1) traceback_example.py :19:produce_exception(): raise RuntimeError()
🌐
Python Morsels
pythonmorsels.com › reading-tracebacks-in-python
Deciphering Python's Traceback (most recent call last) - Python Morsels
January 3, 2022 - When Python encounters an exception that isn't handled in your code, it will print out a traceback. Tracebacks are supposed to be read from the bottom upward: the very last line in a traceback is the first line that you're supposed to read.
🌐
Martin Heinz
martinheinz.dev › blog › 66
Creating Beautiful Tracebacks with Python's Exception Hooks | Martin Heinz | Personal Website & Blog
February 1, 2022 - If you want to just check out a sample output without writing Python code, then you can also use python -m rich.traceback. Another popular option is better_exceptions. It also produces nice output, but requires a little more setup: # https://github.com/Qix-/better-exceptions # pip install better_exceptions # export BETTER_EXCEPTIONS=1 import better_exceptions better_exceptions.MAX_LENGTH = None # Check if you TERM variable is set to `xterm`, if not set below variable, # See issue: https://github.com/Qix-/better-exceptions/issues/8 better_exceptions.SUPPORTS_COLOR = True better_exceptions.hook() do_stuff() # Raises ValueError
🌐
Python.org
discuss.python.org › python help
How to get a full stack summary from a traceback.TracebackException - Python Help - Discussions on Python.org
January 30, 2024 - Hi, The docs say that a TracebackException’s stack attribute is a stack summary but it seems to be only a frame. How can I get the stack from the tbe? I would like to save a TracebackException object in one process and log a stack trace later in another. The snippet below prints tbe.stack=[ ] Similarly, traceback.TracebackException.from_exception(e).format() does not include function a; however traceback.format_stack() has both a an...
🌐
Acid & Base
sceweb.sce.uhcl.edu › helm › WEBPAGE-Python › documentation › python_tutorial › lib › module-traceback.html
3.6 traceback -- Print or retrieve a stack traceback.
A ``pre-processed'' stack trace ... with leading and trailing whitespace stripped; if the source is not available it is None. print_exception (type, value, traceback[, limit[, file]])...
🌐
O'Reilly
oreilly.com › library › view › python-cookbook › 0596001673 › ch14s05.html
Getting More Information from Tracebacks - Python Cookbook [Book]
July 19, 2002 - """ tb = sys.exc_info( )[2] while 1: if not tb.tb_next: break tb = tb.tb_next stack = [] f = tb.tb_frame while f: stack.append(f) f = f.f_back stack.reverse( ) traceback.print_exc( ) print "Locals by frame, innermost last" for frame in stack: print print "Frame %s in %s at line %s" % (frame.f_code.co_name, frame.f_code.co_filename, frame.f_lineno) for key, value in frame.f_locals.items( ): print "\t s = " % key, # We have to be VERY careful not to cause a new error in our error # printer! Calling str( ) on an unknown object could cause an # error we don't want, so we must use try/except to catch it -- # we can't stop it from happening, but we can and should # stop it from propagating if it does happen!
Authors: Alex MartelliDavid Ascher
Published: 2002
Pages: 608
🌐
Bacancy Technology
bacancytechnology.com › qanda › python › python-try-except-print-error
How to print as exception in Python
July 31, 2023 - Traceback (most recent call last): ... ‘variable_that_does_not_exist’ is not defined The traceback.format_exc() function will print a detailed stack trace of the exception....