If you've ever run a Python script and seen it die with:

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

…you've hit a segmentation fault. Your Python process crashed at the C level, and no Python traceback was printed because the interpreter itself was killed by the operating system. This article walks through what SIGSEGV means, the most common causes (based on the popular Stack Overflow thread Process finished with exit code 139), and — most importantly — the #1 cause and its fix: using a non-interactive matplotlib backend.

for more Python or Pycharm errors check:

What does SIGSEGV actually mean?

SIGSEGV (signal 11, "segmentation violation") is sent by the OS when a process tries to read from or write to a memory address that isn't mapped into its address space.

In a pure-Python program this is almost never a bug in your code — Python raises exceptions for that. A segfault usually means:

  • A C extension module (NumPy, OpenCV, TensorFlow, PyTorch, wxPython, PyQt, matplotlib's GUI backends, pyodbc, scikit-learn, etc.) did something illegal with memory.
  • The Python interpreter itself was built with a broken toolchain.
  • Two native libraries in the same process are conflicting (e.g. two different OpenMP runtimes, two Qt versions).

Because the crash happens below Python, you get no traceback — just the exit code.


Cause #1 — matplotlib using an interactive GUI backend (the most common)

This is the single most frequent cause in IDE environments like PyCharm, VS Code, and Jupyter on macOS and Linux, and it happens even in scripts that "should" work.

The problem

By default, matplotlib picks a GUI backend based on your OS:

OS Default backend
macOS MacOSX (Cocoa)
Windows TkAgg or QtAgg
Linux TkAgg or QtAgg

These backends spin up a native event loop and require a main thread with a running windowing system. When you:

  • run a script inside an IDE debugger,
  • mix matplotlib with Selenium, wxPython, PyQt, or threads,
  • run on a headless server or over SSH,
  • call plt.show() after the GUI thread has already been torn down,

…the backend tries to talk to a GUI that doesn't exist or has already been destroyed → SIGSEGV.

Minimal reproduction

import matplotlib.pyplot as plt

plt.plot([1, 2, 3], [4, 5, 6])
plt.show()

On macOS in PyCharm this frequently crashes with exit code 139 the moment plt.show() is called, or right after the window is closed.

The fix — use the Agg backend

Agg is a pure C, non-interactive rasterizer. It has no GUI, no event loop, no windowing system dependency. It cannot segfault on show() because show() is a no-op.

import matplotlib
matplotlib.use("Agg")          # MUST come BEFORE importing pyplot
import matplotlib.pyplot as plt

plt.plot([1, 2, 3], [4, 5, 6])
plt.savefig("chart.png")       # <-- save instead of show

Three rules to make this work:

  1. Set the backend before importing pyplot. pyplot binds to a backend the moment it's imported. If you do import matplotlib.pyplot as plt first and then matplotlib.use("Agg"), it's too late — you'll get a warning and the GUI backend stays active.
  2. Replace plt.show() with plt.savefig(...). Agg has no window to show.
  3. Call plt.close(fig) after saving to release the C-side memory.

Crash-safe pattern

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.plot([1, 2, 3], [4, 5, 6])

plt.savefig("chart.png", dpi=150, bbox_inches="tight")
plt.close(fig)                 # free memory

print("✅ Saved chart.png")

If you're in a Jupyter notebook and still want inline figures, use:

%matplotlib inline

or, if you're on a headless server:

%matplotlib agg

Bonus: how to verify which backend is active

import matplotlib
print(matplotlib.get_backend())

If this prints MacOSX, TkAgg, or QtAgg, and your script crashes, switch to Agg.

Bonus: environment-variable override

You can also force the backend globally without touching the code:

export MPLBACKEND=Agg
python your_script.py

or, per-run:

MPLBACKEND=Agg python your_script.py

This is handy in CI pipelines and Docker images.


Cause #2 — Mixing Selenium (or any GUI library) with matplotlib

Even with Agg, if you run Selenium and matplotlib in the same Python process, you can still get SIGSEGV on shutdown. The crash usually happens after your script finishes, when Python tears down the interpreter and both C libraries try to free the same resources.

Fix: split the workflow, or use os._exit(0)

Option A — split into two scripts:

Script Job
scrape.py Selenium only → writes data.json, then driver.quit()
analyze.py pandas + matplotlib only → reads data.json, builds chart

Option B — one script, but skip interpreter teardown:

import os

# ... everything runs here ...

driver.quit()
plt.savefig("chart.png")
plt.close("all")

os._exit(0)     # skip Python's atexit/GC — this is where SIGSEGV often fires

os._exit(0) bypasses normal cleanup and exits the process immediately.


Other common causes reported on the Stack Overflow thread

The SIGSEGV question has accumulated 24+ answers over the years, each pointing at a different culprit. Here's the complete map, grouped by category:

1. GUI / windowing libraries

  • wxPython — destroying a frame while the main loop is running (the original question).
  • PyQt / PySide — turning off PyQt compatibility in the PyCharm debugger actually fixes it for many users. In PyCharm: Settings → Build, Execution, Deployment → Python Debugger → Collect runtime types — toggle it.
  • matplotlib — GUI backend mismatch (see Cause #1).

2. Deep-learning frameworks

  • TensorFlow — new versions crash on older CPUs/GPUs. Fix: downgrade (e.g. tensorflow==1.4, or tensorflow-gpu==1.9.0).
  • PyTorch — versions > 2.0.1 crash on some Macs. Downgrade or upgrade to a build matching your macOS version.
  • MONAI — importing monai crashed until a fresh conda environment was created. Naming the env the same as the package also caused issues.

3. Scientific / ML stack

  • scikit-learn — KMeans segfaulted on some versions. Fix: upgrade to 1.0.2+, or pip uninstall scikit-learn && pip install scikit-learn.
  • NumPy — version 1.24.3 fixed a SIGSEGV triggered by import cv2. Downgrading NumPy to 1.24.3 is a widely reported fix.
  • OpenCVcv2.SIFT()cv2.SIFT_create(). Also cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml").

4. GPU / hardware

  • PyOpenCL — pointing at a GPU context that isn't connected. Fix: change os.environ['PYOPENCL_CTX'] to the right index.
  • General memory issues — rebooting the machine resolved it in a few cases.

5. Database drivers

  • pyodbc / Oracle — opening the same connection multiple times, or hitting a breakpoint while the connection is open. Fix: open once and reuse, or close properly after use.

6. Concurrency

  • concurrent.futures — nesting .map() inside another .map() call. Fix: remove one of the .map calls.
  • requests with a client certificate in threads — switched to httpx and the crash disappeared.

7. File / I/O

  • Writing to a file that's still open — close the file and rerun.
  • Pickled pandas DataFrame — corrupted .p file. Delete and regenerate.

8. Environment / packaging

  • Corrupted virtualenv — delete the interpreter and the venv/ folder, recreate.
  • Recent conda installs — revert the most recent conda install commands.
  • Conflicting librariespyspark in an env with other big-data packages.
  • PHP / PHPUnit — a circular dependency (yes, other languages report the same exit code).

9. Debugging tools

  • GDB — run gdb --args python your_script.py, then run inside GDB. When it crashes, use bt to see the C stack trace and identify the offending library.
  • faulthandlerpython -X faulthandler your_script.py prints a Python-level C traceback at crash time. The fastest way to identify which extension module died.

Some answers suggest:

import signal
signal.signal(signal.SIGSEGV, signal.SIG_IGN)

Don't do this. Ignoring SIGSEGV leaves your process in an undefined state — memory corruption will silently propagate and produce wrong results. Fix the root cause instead.


Quick decision tree

SIGSEGV in Python?
│
├─ Does the script use matplotlib?
│   └─ YES → Set matplotlib.use("Agg") BEFORE importing pyplot.
│             Replace plt.show() with plt.savefig().
│             Add plt.close(fig) and os._exit(0).
│
├─ Does the script use Selenium / PyQt / wxPython?
│   └─ YES → Split the script, or exit with os._exit(0).
│             In PyCharm, toggle "Collect runtime types" in the debugger.
│
├─ Does the script use TensorFlow / PyTorch / OpenCV / sklearn?
│   └─ YES → Check versions. Downgrade or upgrade the offending package.
│             Try a fresh conda/venv environment.
│
├─ Does the script use threads or concurrent.futures?
│   └─ YES → Remove nested .map() calls.
│
└─ Still crashing?
    └─ Run with faulthandler:  python -X faulthandler script.py
        Or with GDB:           gdb --args python script.py

TL;DR

Symptom Most likely cause Fix
Crash on plt.show() GUI backend (MacOSX/TkAgg/QtAgg) matplotlib.use("Agg") before importing pyplot
Crash on IDE shutdown Interpreter teardown conflict End script with os._exit(0)
Crash with Selenium + matplotlib Mixed C libraries Split into two scripts
Crash importing TF/PyTorch/cv2 Version mismatch Downgrade/upgrade the package
Crash in PyCharm debugger Debugger bug Toggle "Collect runtime types"
Crash with no pattern Corrupted venv / env Delete and recreate the environment

The single most impactful fix — and the one that resolves the majority of cases in IDE environments — is:

import matplotlib
matplotlib.use("Agg")          # MUST come before importing pyplot
import matplotlib.pyplot as plt

plt.plot([1, 2, 3], [4, 5, 6])
plt.savefig("chart.png")       # use savefig, not show

Do that, add plt.close(fig) and os._exit(0), and the vast majority of SIGSEGV crashes in data-science and scraping scripts disappear.