Question

Print Full Python Exception Tracebacks Without Exiting

pythonexceptiontry-catchtraceback

Question

How can I catch an exception in Python, print and log its complete traceback, and then allow the program to continue running?

For example:

try:
    do_stuff()
except Exception as err:
    print(Exception, err)
    # Print the complete traceback here, not only the exception type and message.

I want output equivalent to Python's normal unhandled-exception traceback, but I do not want the exception to terminate the program.

Short Answer

You will learn how Python exception handling changes traceback output, how to print the active exception's full traceback with the traceback module, and how to log failures while safely continuing with later work.

Concept

When an exception is unhandled, Python prints a traceback and terminates the current program flow. A traceback shows:

  • the sequence of function calls that led to the failure,
  • the source file and line number at each call,
  • the line of code that failed, when available,
  • the exception type and message.

Once an except block catches the exception, it is no longer unhandled. Python therefore does not automatically display its traceback. The exception information is still available inside that except block, and the standard-library traceback module can format or print it.

Use traceback.print_exc() inside an except block to print the traceback for the exception currently being handled:

import traceback

try:
    do_stuff()
except Exception:
    traceback.print_exc()
    # Execution continues after this block.

traceback.print_exc() writes to standard error (sys.stderr) by default, like Python's usual exception display. Catching Exception is usually appropriate for application errors. It intentionally does not catch control-flow exceptions such as KeyboardInterrupt and SystemExit.

Mental Model

Think of a traceback as a route history for a delivery that failed.

  • Each function call is a stop on the route.
  • The exception is the delivery problem.
  • An unhandled exception makes Python automatically print the route history and stop the delivery service.
  • A try/except block is a support desk that intercepts the problem.

After intercepting it, the support desk must explicitly ask for the route history with traceback.print_exc(). It can then record the problem and let the rest of the service continue.

Take Quiz

Syntax and Examples

Import Python's built-in traceback module and call print_exc() from within except.

import traceback

def divide(total, count):
    return total / count

try:
    result = divide(10, 0)
    print(result)
except Exception:
    traceback.print_exc()

print("The program is still running.")

Typical output includes the call stack and the final error:

Traceback (most recent call last):
  File "example.py", line 7, in <module>
    result = divide(10, 0)
             ^^^^^^^^^^^^^
  File "example.py", line 4, in divide
    return total / count
           ~~~~~~^~~~~~~
ZeroDivisionError: division by zero
The program is still running.

If you also need the exception object for a custom message, keep as err:

import traceback

try:
    do_stuff()
except Exception as err:
    print(f"Task failed: {err}")
    traceback.print_exc()

Avoid print(Exception, err). Exception is the base exception class, not necessarily the type that was raised. Use type(err).__name__ if you only need the actual type name:

print(f"{type(err).__name__}: {err}")

Step by Step Execution

Consider this program:

import traceback

def load_port(value):
    return int(value)

def start_server():
    port = load_port("not-a-number")
    print(f"Starting on port {port}")

try:
    start_server()
except Exception as err:
    print(f"Could not start server: {err}")
    traceback.print_exc()

print("Performing other startup tasks.")

Execution proceeds as follows:

  1. Python enters the try block and calls start_server().
  2. start_server() calls load_port("not-a-number").
  3. int("not-a-number") raises ValueError.
  4. Python leaves load_port() and start_server() while looking for a matching handler.
  5. The except Exception as err block matches the ValueError and stores it in err.
  6. traceback.print_exc() prints the active exception's complete call stack, including load_port, start_server, and the module-level call.
  7. The except block ends normally.
  8. Python executes print("Performing other startup tasks."); the program has not exited.

The traceback can appear after or before normal print() output depending on output buffering because tracebacks are normally written to stderr while print() writes to stdout.

Real World Use Cases

Full tracebacks are useful whenever an application can recover from one failed unit of work.

  • Batch import jobs: Log the traceback for one malformed CSV row, skip it, and continue importing later rows.
  • Background workers: Record why one queued task failed without stopping the worker process.
  • Web applications: Log a detailed traceback on the server, then return a safe error response to the client.
  • Scheduled scripts: Continue processing other reports or accounts after one API request fails.
  • Command-line tools: Report a failed optional operation while still completing independent operations.
  • Plugin systems: Prevent one third-party plugin failure from crashing the host application.

In production, send tracebacks to logs rather than exposing them to end users. A traceback can contain internal file paths, implementation details, and sometimes sensitive data included in error messages.

Take Quiz

Real Codebase Usage

In real projects, developers typically use the logging module rather than direct print() calls. logger.exception() is designed for this: when called inside an except block, it logs a message plus the current exception traceback.

import logging

logging.basicConfig(level=logging.ERROR)
logger = logging.getLogger(__name__)

try:
    do_stuff()
except Exception:
    logger.exception("do_stuff failed; continuing with the next task")

For batch work, handle exceptions at the boundary of each independent item:

import logging

logger = logging.getLogger(__name__)

for filename in filenames:
    try:
        process_file(filename)
    except Exception:
        logger.exception("Could not process %s", filename)
        continue

This approach lets one bad file fail while subsequent files are still processed.

A good recovery handler does more than print an error. It should decide what happens next: skip an item, use a fallback value, retry a temporary operation, or stop cleanly if continuing would create incorrect results. Do not continue merely because it is possible; continue only when the program remains in a valid state.

Common Mistakes

Printing only the exception message

try:
    do_stuff()
except Exception as err:
    print(err)

This prints a message such as division by zero, but not the path of calls that caused it. Use traceback.print_exc() or logger.exception() as well.

Printing Exception instead of the raised type

except Exception as err:
    print(Exception, err)

Exception is the base class, so this does not tell you whether the actual error was ValueError, KeyError, or another subtype.

except Exception as err:
    print(type(err).__name__, err)

For debugging, the full traceback is usually more useful.

Calling traceback.print_exc() outside except

import traceback

traceback.print_exc()  # No active exception to print.

print_exc() uses the exception currently being handled. Call it inside the matching except block. If you saved exception details for later, use traceback.format_exception() with the saved traceback instead.

Catching BaseException

try:
    do_stuff()
except BaseException:
    traceback.print_exc()

This also catches KeyboardInterrupt and SystemExit, which usually should retain their normal behavior. Prefer except Exception: unless you have a specific reason otherwise.

Silently ignoring a failure

try:
    do_stuff()
except Exception:
    pass

This hides useful diagnostic information and can leave the application in an unexpected state. At minimum, log the failure and deliberately choose a recovery action.

Assuming continuation is always safe

Catching an exception does not undo partial changes. For example, a failed database or file operation may have completed part of its work. Use transactions, cleanup code, validation, or retries where appropriate before continuing.

Comparisons

ApproachWhat it outputsDoes execution continue?Best use
No try/exceptPython automatically prints the tracebackNoFail-fast scripts and debugging during development
print(err)Exception message onlyYesBrief user-facing message, usually alongside logging
traceback.print_exc()Current exception's full tracebackYesSimple scripts and debugging handlers
logging.exception("message")A log message plus the current tracebackYesProduction applications and services
raise inside exceptRe-raises the same exception and tracebackUsually no, unless an outer handler catches itLog locally but let a higher layer decide recovery

traceback.print_exc() and logging.exception() must be used while handling an exception. If you need a traceback as a string for storage or an API response, use traceback.format_exc():

import traceback

try:
    do_stuff()
except Exception:
    details = traceback.format_exc()
    save_error_report(details)

Unlike print_exc(), format_exc() returns a string instead of writing it immediately.

Take Quiz

Cheat Sheet

import traceback

try:
    do_stuff()
except Exception:
    traceback.print_exc()  # Prints active traceback to stderr.
# Include a custom message and the traceback.
try:
    do_stuff()
except Exception as err:
    print(f"Failed: {err}")
    traceback.print_exc()
# Production-style logging.
import logging

logger = logging.getLogger(__name__)

try:
    do_stuff()
except Exception:
    logger.exception("do_stuff failed")
# Get the traceback as text instead of printing it.
try:
    do_stuff()
except Exception:
    text = traceback.format_exc()

Key rules:

  • Call print_exc(), format_exc(), or logger.exception() inside except.
  • Prefer except Exception: over except BaseException:.
  • print() normally uses stdout; tracebacks normally use stderr.
  • Catch errors at a level where you can safely recover or make a clear decision to stop.
  • Use raise if you want to log an error locally but still propagate it upward.

FAQ

How do I print a full traceback in a Python except block?

Import traceback and call traceback.print_exc() inside the except block.

except Exception:
    traceback.print_exc()

Does traceback.print_exc() stop the Python program?

No. It only prints the traceback of the exception currently being handled. Execution continues after the except block unless you use raise, return, break, or another control-flow statement.

Why does print(err) not show the traceback?

err contains the exception object, whose string form usually includes only its message. The traceback is separate call-stack information managed by Python's exception machinery.

How can I log an exception and its traceback in Python?

Use logger.exception() inside an except block.

except Exception:
    logger.exception("Request processing failed")

Should I use except Exception or a bare except?

Usually use except Exception. A bare except also catches KeyboardInterrupt and SystemExit, which commonly should not be swallowed.

Can I save a traceback to a string?

Yes. Call traceback.format_exc() inside except; it returns the formatted traceback as a string.

Why is traceback output in a different order from my print() output?

Tracebacks are sent to standard error, while print() uses standard output. These streams can be buffered differently. Use logging for consistent production output handling.

Take Quiz

Mini Project

Description

Build a small batch processor that attempts to convert a list of text values to integers. Invalid values should produce complete tracebacks, but the processor must continue handling the remaining values. This mirrors import scripts and background jobs where one bad record should not stop all work.

Goal

Process every input value, collect valid integers, and print a complete traceback for each invalid value without terminating the program.

Requirements

  1. Create a list containing both valid integer strings and invalid values.
  2. Process each value independently in a loop.
  3. Convert valid values to integers and store them in a results list.
  4. Catch conversion failures and print their full traceback.
  5. Continue processing values after each failure.
  6. Print the successful results at the end.
Take Quiz

Keep learning

Related questions

View more