Python
Debugging
Error Handling
PDB
Automation

Starting python debugger automatically on error

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

When a Python script crashes in the middle of a long run, the most useful information is the state of the program at the moment of failure. Instead of re-running the script and trying to guess where to add breakpoints, you can drop straight into the debugger as soon as an unhandled exception appears.

Use Post-Mortem Debugging with pdb

The built-in pdb module supports post-mortem debugging. That means you let the exception happen, capture its traceback, and then open an interactive debugger at the failing frame.

For one script, the clearest pattern is to wrap main() in a try block:

python
1import pdb
2import traceback
3
4
5def divide_total(total, count):
6    return total / count
7
8
9def main():
10    values = [10, 20, 30]
11    print(divide_total(sum(values), 0))
12
13
14if __name__ == "__main__":
15    try:
16        main()
17    except Exception:
18        traceback.print_exc()
19        pdb.post_mortem()

When the division-by-zero error occurs, Python prints the traceback and opens a pdb prompt. From there you can inspect variables with commands such as p total, p count, where, and up.

This approach is often better than adding pdb.set_trace() manually because it preserves the real failing path rather than a guessed checkpoint.

Install a Global Exception Hook for Scripts

If you want the same behavior across a script without wrapping every entry point, use sys.excepthook. Python calls it for uncaught exceptions on the main thread.

python
1import pdb
2import sys
3import traceback
4
5
6def debug_excepthook(exc_type, exc_value, exc_traceback):
7    traceback.print_exception(exc_type, exc_value, exc_traceback)
8    pdb.post_mortem(exc_traceback)
9
10
11sys.excepthook = debug_excepthook
12
13
14def parse_number(text):
15    return int(text)
16
17
18print(parse_number("not-a-number"))

This is useful for command-line utilities because you can enable it once near startup. It also keeps the rest of the application code clean.

For ad hoc investigation, Python already ships a zero-code option:

bash
python -m pdb my_script.py

That starts the program under the debugger immediately. It is helpful when you want step-by-step execution from the beginning, but it is slower than post-mortem debugging when the bug appears late in the run.

Make the Behavior Optional

Automatically opening a debugger is excellent in local development and annoying in production. A simple pattern is to guard it with an environment variable so you can opt in only when needed.

python
1import os
2import pdb
3import sys
4import traceback
5
6
7def maybe_install_debug_hook():
8    if os.getenv("DEBUG_ON_ERROR") != "1":
9        return
10
11    def debug_excepthook(exc_type, exc_value, exc_traceback):
12        traceback.print_exception(exc_type, exc_value, exc_traceback)
13        pdb.post_mortem(exc_traceback)
14
15    sys.excepthook = debug_excepthook
16
17
18maybe_install_debug_hook()
19
20
21def load_user_age(record):
22    return int(record["age"])
23
24
25print(load_user_age({"name": "Ana"}))

Run it like this:

bash
DEBUG_ON_ERROR=1 python app.py

That keeps the debugger out of normal execution while still making the feature easy to turn on during troubleshooting.

If you use IPython, there is a similar workflow with %pdb on, which enables automatic post-mortem debugging in that interactive environment.

Common Pitfalls

The biggest mistake is enabling automatic debugging in environments where no one can interact with the process. A stuck production worker waiting at a pdb prompt is worse than a normal crash because it can hold resources open and look like a hang.

Another issue is swallowing exceptions before they reach the hook. If your code has a broad except Exception block that logs and continues, sys.excepthook never runs. In those cases, call pdb.post_mortem(tb) explicitly inside the handler while you are investigating.

Threading and asynchronous execution can also change the behavior you expect. sys.excepthook is mainly for uncaught exceptions on the main thread. If a worker thread fails, you may need thread-specific error handling or framework-specific hooks.

Finally, remember that pdb is interactive text I/O. If your program runs under a service manager, inside a non-interactive container, or through a background job system, the debugger may open but be unusable.

Summary

  • 'pdb.post_mortem() is the simplest way to jump into the debugger after a crash.'
  • Wrapping main() in try and except is a clear pattern for single scripts.
  • 'sys.excepthook lets you enable automatic debugging for uncaught exceptions globally.'
  • Guard debugger activation behind an environment variable outside local development.
  • Avoid relying on automatic pdb sessions in non-interactive or production environments.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.