Python faulthandler: Diagnose Crashes

Published on: August 27, 2026
Reading time: 8 minutes
A developer typing code on a laptop with a Python book beside in an office.

The faulthandler module helps diagnose severe failures that can terminate a process before Python produces a normal traceback. It can dump Python stacks when the process receives a segmentation fault, abort, bus error, illegal instruction, timeout, or an operator-requested signal. It is especially useful in applications that rely on native extensions, scientific libraries, drivers, bindings, long-running services, multiprocessing, and tests that hang intermittently.

The module does not repair the failure and does not replace a native debugger. Its purpose is to preserve enough context to show where Python threads were when the process failed or stopped making progress. Because the runtime may already be corrupted, output is intentionally minimal and should be written to a reliable file or stream.

Enable faulthandler

The simplest approach is to call faulthandler.enable() near application startup.

import faulthandler

faulthandler.enable()

Output goes to sys.stderr by default. Enable it before importing suspicious native modules or starting worker threads so early crashes are captured too.

Enable it with an environment variable

Production systems may need diagnostics without a code deployment.

PYTHONFAULTHANDLER=1 python app.py

This is convenient in containers, test commands, scheduled jobs, and incident response. It also works when a crash happens during imports before normal initialization reaches your configuration code.

Use the -X option

The interpreter accepts -X faulthandler.

python -X faulthandler app.py

Document this switch in operational runbooks. A diagnostic feature is less useful if the team must research how to activate it during an outage.

Which failures are captured

On supported platforms, the module installs handlers for fatal signals such as SIGSEGV, SIGFPE, SIGABRT, SIGBUS, and SIGILL. Exact availability depends on the operating system and Python build.

These failures commonly indicate memory corruption, invalid native arithmetic, an explicit abort, an invalid address, or an unsupported machine instruction. Pure Python code rarely causes them directly; native extensions and external libraries are typical suspects.

Fatal dumps versus regular tracebacks

A regular Python exception unwinds frames, executes finally blocks, and can be caught. A fatal native error may stop the runtime immediately. Faulthandler tries to write stack information using a restricted implementation that does not depend on normal traceback machinery.

The result may omit local values and show only filenames, function names, and line numbers. That limited information is still often enough to identify the active subsystem.

Write to a dedicated file

Service stderr may be lost, truncated, or mixed with high-volume logs. Open a dedicated file and keep it alive for the entire time the handler is enabled.

import faulthandler

crash_log = open("python-faults.log", "a", buffering=1)
faulthandler.enable(file=crash_log, all_threads=True)

Do not close the file while faulthandler may still use it. The module retains the underlying descriptor and does not automatically reopen a replacement.

Log rotation

If an external rotator renames or replaces the file, the old descriptor may continue pointing to the previous inode. Reopen the destination and configure the handler again, or use stderr and let the container or service manager collect it.

Test the exact rotation strategy in the same environment used by production.

Dump all threads

The all_threads=True

faulthandler.dump_traceback(all_threads=True)

This is critical when one thread is waiting for another. The thread that requests the dump may not be the thread responsible for a deadlock.

Generate a manual dump

dump_traceback() writes stacks without terminating the process.

import faulthandler

faulthandler.dump_traceback()

Use it in protected administrative commands, internal watchdogs, support tooling, and controlled tests. Never expose dumps publicly because source paths and architecture details can be sensitive.

Schedule a timeout dump

dump_traceback_later() schedules a dump if an operation exceeds a deadline.

faulthandler.dump_traceback_later(
    30,
    repeat=False,
    file=crash_log,
    exit=False,
)
try:
    run_operation()
finally:
    faulthandler.cancel_dump_traceback_later()

This pattern is valuable for tests that sometimes hang, slow startup, blocked shutdown, and native calls that fail to return.

Repeat dumps

With repeat=True, the module writes stacks at regular intervals.

Several snapshots help distinguish a static deadlock from a slow process that is still moving. Repeated dumps can create substantial volume, so define retention and cancel the timer as soon as the incident ends.

Exit after a timeout

The exit=True

Use it only when a supervisor can replace the process and continued execution would be unsafe. Immediate exit skips ordinary cleanup, may leave buffers unflushed, and can interrupt transactions.

Register an operator signal

On Unix-like systems, register() can attach a dump to a user signal.

import faulthandler
import signal

faulthandler.register(
    signal.SIGUSR1,
    all_threads=True,
    chain=False,
)

An authorized operator can then send the signal to a PID and obtain stacks without stopping the process.

Choose the signal carefully

Do not overwrite a signal already used by the application, server, runtime, or observability agent. Document the selected signal and test for conflicts.

Inside containers, verify that the signal reaches the Python process. A shell running as PID 1 may not forward it as expected.

The chain parameter

With chain=True, the previous signal handler runs after the dump. This can preserve another diagnostic tool, but it may also execute logic that is unsafe in signal context.

Test the combination on the same platform and runtime used in production.

Unregister a signal

unregister(signum) removes the module’s handler.

faulthandler.unregister(signal.SIGUSR1)

Use it when unloading a plugin, changing diagnostics, or cleaning up tests that modify global signal state.

Check whether it is enabled

is_enabled() reports whether fatal-error handlers are active.

if not faulthandler.is_enabled():
    faulthandler.enable()

This is helpful in executables and frameworks. A reusable library should generally let the application decide whether to install global handlers.

Avoid hidden activation in libraries

A library should not silently replace stderr behavior, signal handlers, or global files. Offer an explicit configuration hook and let the executable own the decision.

Global handlers may conflict with notebooks, test runners, embedded interpreters, and application servers.

Test-runner integration

Enable the module when tests involve native extensions, threads, or subprocesses.

python -X faulthandler -m pytest

For a test that can hang, schedule a deadline slightly longer than the expected duration. The resulting stacks often identify the fixture, lock, queue, or native call that is stuck.

Multiprocessing

Every process has its own interpreter and must enable faulthandler independently. A parent-process dump does not automatically show child threads.

def initialize_worker():
    faulthandler.enable()

Use separate files by PID or a centralized stderr collector so simultaneous outputs remain understandable.

Threads

All-thread dumps reveal locks, conditions, queues, and blocking I/O. Give threads descriptive names to improve related logs and debugger views.

threading.Thread(
    target=worker,
    name="customer-importer",
)

Faulthandler focuses on frames, but consistent naming improves the rest of the incident evidence.

Concurrent futures

A thread pool can appear frozen when every worker waits for another future from the same executor. Repeated dumps show many threads blocked in Future.result().

See Python concurrent.futures for structural deadlock prevention.

Native extensions

If the final Python frame calls a native extension, the underlying fault may be inside C, C++, Rust, Fortran, a GPU runtime, or a driver. Record library versions, architecture, operating system, inputs, and reproduction steps.

The Python stack identifies the native boundary, but GDB, LLDB, WinDbg, sanitizer builds, or vendor tools may still be required.

C stack support

Recent versions and selected builds can provide additional native-stack information in supported environments. Availability depends on platform, build options, and debug symbols.

Treat native-stack output as a supplement. Unstripped binaries and symbol packages make it far more useful.

File descriptor lifetime

The module writes through the descriptor associated with the stream. If the file is closed and that descriptor number is reused, output may be written to an unrelated destination.

Keep ownership explicit and close the file only after disabling the handler or terminating the process.

Disable when required

disable() removes fatal handlers installed by the module.

faulthandler.disable()

This may be necessary in tests for custom handlers or embedded applications. In ordinary services, leaving it enabled has little overhead until a dump is requested.

Dump security

Dumps deliberately omit many local values, but they can still reveal filesystem paths, internal function names, customer-specific modules, and service architecture.

Protect files, limit access to diagnostic signals, apply retention rules, and sanitize reports before posting them publicly.

Privacy in multi-tenant services

An all-thread dump may reveal which operations several customers are running at the same time. Treat it as sensitive operational data.

Do not expose dump generation through an unauthenticated endpoint. Require strong authorization and audit every use.

Watchdogs

An external watchdog can request a dump before restarting an unresponsive process. This preserves evidence while allowing automated recovery.

Use two deadlines: first diagnostics, then termination. The process gets an opportunity to recover, and the operator receives context if it remains stuck.

Deadlock versus slow progress

One dump shows a position; several dumps show movement. Changing line numbers suggest slow progress. Identical frames in waits and locks suggest a deadlock or a permanently blocked external operation.

Combine stacks with CPU, I/O, queue depth, memory, and latency metrics.

It does not replace logging

Logs explain the semantic sequence before a failure. Faulthandler shows thread positions at a critical instant. Use both.

Include operation IDs and component versions in logs so a dump can be matched to a request or job.

It does not replace core dumps

A core dump preserves native memory and process state for deep analysis, but it is larger and can contain secrets. Faulthandler is lightweight and fast.

For difficult incidents, configure both according to security and retention policy.

Limitations

No handler runs after SIGKILL, a power loss, or some immediate external termination. Severe corruption can also prevent complete output.

The module does not automatically detect every deadlock and cannot explain the internal state of arbitrary native libraries.

Test the diagnostic path

Do not wait for a real crash. Trigger manual dumps in a controlled environment and verify the destination, permissions, rotation, collection, and alerting.

Repeat the test in containers, service managers, Windows services, and multiprocessing workers.

Common mistakes

Common failures include enabling too late, closing the handler file, assuming a timeout stops work without exit, registering a conflicting signal, exposing dumps publicly, expecting complete native details, and enabling only in the parent process.

Conclusion

faulthandler is a simple and valuable diagnostic layer for crashes, deadlocks, and hangs. Enable it early, preserve output in a reliable destination, use signals or timeouts for on-demand snapshots, and include all threads.

Combine the report with logs, metrics, and native debuggers when C extensions are involved. Consult the official faulthandler documentation and Python dis for inspecting bytecode near a failing path.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    A developer typing code on a laptop with a Python book beside in an office.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python linecache: Read Source Lines

    Learn Python linecache to retrieve source lines, refresh cached files, support tracebacks and loaders, preserve indentation, and secure paths.

    Ler mais

    Tempo de leitura: 7 minutos
    27/08/2026
    Detailed view of programming code in a dark theme on a computer screen.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python symtable: Analyze Name Scopes

    Learn Python symtable to analyze scopes, locals, globals, parameters, imports, nonlocals, closures, and compiler namespaces.

    Ler mais

    Tempo de leitura: 9 minutos
    27/08/2026
    A close-up shot showcasing the intricate scales of a snake, highlighting texture and color.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python dis: Understand Bytecode

    Learn Python dis to inspect bytecode instructions, jumps, stack effects, adaptive caches, and optimizations without relying on unstable internals.

    Ler mais

    Tempo de leitura: 6 minutos
    27/08/2026
    A developer typing code on a laptop with a Python book beside in an office.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python tokenize: Read Source Code Tokens

    Learn Python tokenize to read tokens, comments, encodings, indentation, and positions, then transform and rebuild source safely.

    Ler mais

    Tempo de leitura: 6 minutos
    27/08/2026
    High-angle view of woman coding on a laptop, with a Python book nearby. Ideal for programming and tech content.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python zipapp: Build Executable .pyz Files

    Learn Python zipapp to build .pyz files, define entry points, bundle pure dependencies, handle resources, and distribute secure CLI tools.

    Ler mais

    Tempo de leitura: 6 minutos
    27/08/2026
    Close-up view of a computer screen displaying code in a software development environment.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python sysconfig: Paths and Build Info

    Learn Python sysconfig to inspect paths, schemes, headers, compiler flags, ABI details, native extensions, and virtual environments.

    Ler mais

    Tempo de leitura: 6 minutos
    27/08/2026