Skip to content

Access violation (0xC0000005) inside sip.cp314-win_amd64.pyd on Windows/Python 3.14.5, closing a QMainWindow after background QThreadPool work — fixed by 13.11.1 → 13.12.0 #115

Description

@lednicky-t

Summary

A PyQt6 desktop application crashes with a Windows access violation (STATUS_ACCESS_VIOLATION, 0xC0000005) when the main window is closed, but only in sessions where a background QThreadPool/QRunnable worker had loaded and displayed data (image arrays via numpy/tifffile/zarr, rendered with pyqtgraph) earlier in that session. Sessions where nothing was ever loaded close cleanly every time.

The crash produces no Python-level traceback or exception (it bypasses sys.excepthook/threading.excepthook entirely, as expected for a native access violation) — it was only diagnosed via the Windows Application event log's own crash record, which points squarely at PyQt6-sip itself rather than application code.

Upgrading PyQt6-sip from 13.11.1 to 13.12.0 (no other change) eliminated the crash across a subsequent real session that reproduced the same close-after-load pattern that crashed every time before the upgrade.

Environment

  • OS: Windows 11 Pro 10.0.26200
  • Python: 3.14.5 (tags/v3.14.5:5607950, May 10 2026, 10:43:50) [MSC v.1944 64 bit (AMD64)]
  • PyQt6: 6.11.0
  • PyQt6-Qt6: 6.11.1
  • PyQt6-sip: 13.11.1 (crashes)13.12.0 (does not crash)

Crash signature (from Windows Event Log, Application log, Event ID 1000/1001)

Identical across three independent crash occurrences over two separate sessions:

Faulting application name: python.exe, version: 3.14.5150.1013, time stamp: 0x6a0062cc
Faulting module name: sip.cp314-win_amd64.pyd, version: 0.0.0.0, time stamp: 0x69aebad1
Exception code: 0xc0000005
Fault offset: 0x00000000000107b6
Faulting module path: <venv>\Lib\site-packages\PyQt6\sip.cp314-win_amd64.pyd
Hashed bucket (WER fault bucket): d60846680b1f6807a059806d29041443

Same faulting module, same time stamp, same exact byte offset, and the same WER hashed bucket every time — this reads as a deterministic bug in a specific object-teardown code path, not a timing-dependent race.

Circumstances that reproduce it

  1. A QMainWindow-based app with QApplication.setQuitOnLastWindowClosed(True).
  2. A QThreadPool (QThreadPool(self), a handful of max threads) running QRunnable workers that read files from disk (numpy/tifffile/zarr arrays) and emit results back to the main thread via Qt signals.
  3. Those results get displayed via pyqtgraph (image items, plot curves, ROI overlays).
  4. The user closes the main window normally (clicking the close button / calling .close()), triggering closeEvent(), which does some settings/state saving and then calls super().closeEvent(event).
  5. The process then exits via sys.exit(app.exec()) returning.

Crash happens at or shortly after step 4/5. It never happened in a session where step 2–3 never ran (i.e., the window was closed with nothing ever loaded).

What I was not able to produce

An isolated, dependency-free minimal repro outside the full application. I built one using QT_QPA_PLATFORM=offscreen (same window/QThreadPool/close pattern, synthetic TIFF data, no real display) and could not reproduce the crash there — it hung instead of crashing, which suggests the offscreen platform plugin skips whatever native paint/window-teardown path the real (on-screen) crash goes through. I don't have a minimized script to attach; happy to help narrow this further if it's useful (e.g. testing a debug/symbol build, or a smaller repro under a real display rather than offscreen).

Possibly related (unconfirmed)

pytest-dev/pytest#14500 reports "Windows fatal exception: access violation (GC crash on exit)" also on Python 3.14.5, in an unrelated project. I can't confirm it's the same root cause, but it suggests Python 3.14's shutdown/GC behavior may be exposing latent bugs in multiple C-extension modules that haven't yet fully adapted, not something unique to sip. Flagging in case it's a useful cross-reference.

Expected vs actual

  • Expected: closing the main window and exiting the process cleanly (exit code 0), same as any session where no dataset was loaded.
  • Actual: exit code 3221225477 / 0xC0000005, no Python exception, in sip.cp314-win_amd64.pyd, only in sessions with prior background-thread-loaded data.

Fix confirmed

Upgrading PyQt6-sip 13.11.1 → 13.12.0 (pip install --upgrade PyQt6-sip==13.12.0), with no other code or environment changes, resolved it — verified by reproducing the exact "load a dataset, then close" sequence that crashed reliably before the upgrade.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions