Logging uncaught exceptions in Python
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Python already prints a traceback for uncaught exceptions, but production systems usually need more than output to standard error. You often want uncaught exceptions recorded through the same logging pipeline as the rest of the application so they reach files, monitoring systems, or centralized log collection.
The main technique is to install top-level exception hooks. In modern Python, that often means sys.excepthook for the main thread, threading.excepthook for background threads, and an event-loop exception handler for asyncio code.
Log Main-Thread Uncaught Exceptions with sys.excepthook
Python calls sys.excepthook when an exception reaches the interpreter without being handled. You can replace it with a function that logs the full traceback:
That captures exceptions that would otherwise only print to the terminal.
Cover Background Threads Too
sys.excepthook does not automatically cover exceptions escaping Python threads. For that, use threading.excepthook on modern Python:
Without this, thread failures can be easy to miss, especially in services with worker threads.
Handle asyncio Exceptions Explicitly
Asynchronous programs have another path for uncaught failures. The event loop can report exceptions from tasks or callbacks that no code awaited properly. Install an asyncio exception handler so those also reach your logger:
This is important for async services where background tasks may fail after the original request handler has moved on.
Centralize Logging Setup Early
The hooks need to be installed near process startup. If you configure them only after part of the application has already started threads or event loops, you may miss early failures.
It is also worth deciding what should happen after logging. In many cases, the process should still terminate for an uncaught exception because the program reached an unexpected state. Logging is not the same as recovery.
Distinguish Uncaught from Caught Exceptions
Do not use uncaught-exception hooks as an excuse to stop writing local error handling. The hook is the last line of defense for failures that escaped normal control flow. Regular application errors should still be caught where the program can respond meaningfully.
A useful rule is:
- catch expected failures where you can handle them
- let truly unexpected failures reach the top-level hook so they are logged clearly
Common Pitfalls
- Installing only
sys.excepthookand assuming thread or async failures are covered too. - Swallowing exceptions after logging and leaving the process in an invalid state.
- Forgetting to exempt
KeyboardInterrupt, which makes normal shutdown awkward during development. - Treating uncaught-exception logging as a substitute for proper local exception handling.
Summary
- Use
sys.excepthookto log uncaught exceptions from the main thread. - Use
threading.excepthookfor uncaught exceptions in worker threads. - Use an event-loop exception handler for
asynciotask and callback failures. - Install the hooks early during process startup.
- Log uncaught exceptions for visibility, but still handle expected failures closer to where they occur.

