Current exceptions and sys.excepthook

sys · Practical · 10 min

Crash reporting, logging uncaught errors and friendly CLI error messages all hook in here.

Inside an except block, sys.exception() (3.11+) returns the exception currently being handled, or None outside one. The older sys.exc_info() returns the triple (type, value, traceback); since 3.11 the type and traceback are always derivable from the value (type(e), e.__traceback__). Library code such as logging helpers uses these to access the exception without being passed it.

When an exception escapes the program, Python calls sys.excepthook(type, value, tb), whose default prints the traceback to stderr. Replace it to change that behaviour:

  • Show a one-line message to end users of a CLI, but the full traceback when a --debug flag is set.
  • Send crashes to logging or an error-tracking service.

Keep the original in sys.__excepthook__ and call it for cases you don't handle. An excepthook should never raise.

Related hooks:

  • threading.excepthook handles exceptions escaping threads, which do not go through sys.excepthook.
  • sys.unraisablehook receives exceptions that can't be raised, such as errors in __del__.
  • In asyncio, use the loop's exception handler.

KeyboardInterrupt also passes through the excepthook, so let it fall back to the default when you only want to reformat ordinary errors.

Example

import subprocess
import sys

try:
    {}["missing"]
except KeyError:
    e = sys.exception()
    print(type(e).__name__, e)     # KeyError 'missing'
print(sys.exception())             # None

app = '''
import sys
def hook(exc_type, exc, tb):
    if issubclass(exc_type, KeyboardInterrupt):
        return sys.__excepthook__(exc_type, exc, tb)
    print(f"error: {exc}", file=sys.stderr)   # short message, no traceback
sys.excepthook = hook
raise FileNotFoundError("settings.toml not found")
'''
r = subprocess.run([sys.executable, "-c", app], capture_output=True, text=True)
print(r.returncode, r.stderr.strip())  # 1 error: settings.toml not found

Remember

  • sys.exception() returns the exception being handled (3.11+)
  • Assign sys.excepthook to control how uncaught exceptions are reported
  • Threads use threading.excepthook; delegate unknown cases to sys.__excepthook__

Watch out for

  • Expecting a custom sys.excepthook to catch errors raised in worker threads.

Check yourself

  1. A program sets sys.excepthook to a function that logs the error, then raises ValueError at top level. What is the exit code?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.python.org/3/library/sys.html#sys.excepthook