# How Rich's Traceback Handler Captures and Displays Exception Information

> Discover how Rich's traceback handler captures and displays exception information. Learn how it enhances Python error reporting with syntax-highlighted code and local variables.

- Repository: [Textualize/rich](https://github.com/Textualize/rich)
- Tags: internals
- Published: 2026-03-06

---

**Rich's traceback handler intercepts uncaught exceptions by replacing Python's `sys.excepthook` with a custom callback that walks the raw traceback to extract frame data, then renders syntax-highlighted source code and optional local variables through a console-aware pipeline.**

The Textualize/rich library transforms standard Python error reports into detailed, colorized terminal output. Understanding how Rich's traceback handler captures and displays exception information reveals a sophisticated pipeline that bridges low-level CPython internals with high-level terminal rendering.

## Hook Installation and Interception

Rich begins by replacing the default exception display mechanism with its own renderer.

### Replacing the Global Exception Hook

The entry point is the [`install()`](https://github.com/Textualize/rich/blob/master/rich/traceback.py#L84) function. When called, it stores the existing `sys.excepthook` and substitutes a custom handler. This new hook receives the exception type, value, and raw traceback object whenever an uncaught error bubbles to the top of the stack.

In IPython or Jupyter environments, Rich detects the shell and patches `IPython._showtraceback` instead (see the integration logic at lines [1010‑1025](https://github.com/Textualize/rich/blob/master/rich/traceback.py#L1010)). This ensures the rich output appears even in interactive notebooks that bypass the standard CPython hook.

## Capturing and Structuring Exception Data

Once the hook triggers, Rich converts the raw traceback into a structured, renderable object.

### Building the Traceback Object

The handler immediately delegates to [`Traceback.from_exception()`](https://github.com/Textualize/rich/blob/master/rich/traceback.py#L353). This class method accepts the exception triple (`type_`, `value`, `traceback`) and optional configuration flags such as `show_locals`, `width`, and `suppress`.

### Walking the Stack

Inside `from_exception`, the [`extract()`](https://github.com/Textualize/rich/blob/master/rich/traceback.py#L332) method (lines [332‑424]) performs the heavy lifting. It uses `walk_tb()` to iterate over every frame in the traceback chain, building a list of **Frame** objects. Each **Frame** captures:

- Filename, line number, and function name
- The source line text retrieved via `linecache`
- A boolean indicating whether the frame is part of the user's code or a library
- Optional local variables (when enabled)

The extractor respects frame-local markers such as `_rich_traceback_omit` and `_rich_traceback_guard`, allowing libraries to hide internal frames or reset the traceback guard. It also filters out any paths matching the `suppress` list passed to `install()`.

## Enriching the Display

After structuring the data, Rich enhances each frame with visual context.

### Syntax Highlighting

For every frame, Rich reads the source file and creates a `Syntax` object with guessed lexer via `_guess_lexer`. This happens in the rendering phase (see the **Syntax** creation around line [842](https://github.com/Textualize/rich/blob/master/rich/traceback.py#L842)), which produces colorized code with line numbers aligned to the error location.

### Local Variable Inspection

When `show_locals=True`, Rich traverses the frame's `f_locals` using `pretty.traverse` (lines [588‑595](https://github.com/Textualize/rich/blob/master/rich/traceback.py#L588)). The `render_scope` helper formats these variables into a compact, syntax-highlighted panel, respecting options like `locals_max_length` and `locals_max_string` to prevent massive objects from flooding the terminal.

## Rendering to the Terminal

The final stage converts the structured data into printable renderables.

### The Console Protocol

The **Traceback** class implements `__rich_console__`, starting at line [626](https://github.com/Textualize/rich/blob/master/rich/traceback.py#L626). This method constructs a hierarchy of `Panel` and `Group` objects, wrapping each stack frame in a visual container. It temporarily applies a custom **Theme** that maps Pygments tokens to Rich style names (defined at lines [633‑653](https://github.com/Textualize/rich/blob/master/rich/traceback.py#L633)), ensuring consistent coloring for keywords, strings, and comments across different syntax themes.

### Final Output

The installed exception hook obtains a dedicated console instance and invokes `print(exception_traceback)` (line [164](https://github.com/Textualize/rich/blob/master/rich/traceback.py#L164)), streaming the fully rendered panels to `stderr` or the configured output stream.

## Configuration and Usage Examples

Enable Rich tracebacks with a single call at the start of your application.

```python
from rich.traceback import install

install()
raise ValueError("Demonstration error")

```

To include local variables and suppress specific library paths:

```python
from rich.traceback import install

install(
    show_locals=True,
    suppress=["/usr/local/lib/python3.11/site-packages"]
)

def failing_function():
    data = {"key": "value"}
    raise RuntimeError("Error with context")

failing_function()

```

For manual control outside the global hook:

```python
import sys
from rich.console import Console
from rich.traceback import Traceback

try:
    1 / 0
except ZeroDivisionError:
    console = Console()
    tb = Traceback.from_exception(*sys.exc_info(), show_locals=True)
    console.print(tb)

```

## Summary

- **Hook Replacement**: Rich's `install()` function replaces `sys.excepthook` (and IPython's equivalent) to intercept all uncaught exceptions.
- **Data Extraction**: The handler walks the raw traceback using `walk_tb()` and builds **Frame** and **Stack** objects in `extract()`, respecting filters like `_rich_traceback_omit`.
- **Visual Enrichment**: Source code is highlighted via the `Syntax` class, and locals are rendered using `pretty.traverse` when enabled.
- **Console Rendering**: The **Traceback** object implements `__rich_console__` to generate themed panels, printed to the terminal via the console protocol.

## Frequently Asked Questions

### How do I suppress specific library frames from the traceback?

Pass a list of path strings or modules to the `suppress` argument in `install()`. For example, `install(suppress=[click, "path/to/library"])` hides frames originating from those locations, decluttering the output to show only your application code.

### Does Rich's handler work in Jupyter notebooks?

Yes. Rich detects IPython environments and patches `IPython._showtraceback` automatically (see lines [1010‑1025](https://github.com/Textualize/rich/blob/master/rich/traceback.py#L1010)). This allows the same colorized, local-variable-aware tracebacks to appear in notebook cells without any additional configuration.

### Can I display local variables for every frame?

Set `show_locals=True` when calling `install()`. This triggers the local variable renderer for every frame, using `pretty.traverse` to format objects. You can limit output size with `locals_max_length` and `locals_max_string` parameters to avoid overwhelming the terminal with large data structures.

### How do I revert to the default Python traceback handler?

Store the return value of `install()` (the original hook) and reassign it to `sys.excepthook` when needed. The `install()` function returns the previous exception hook, allowing you to restore standard behavior by running `sys.excepthook = original_hook`.