pytorch - 💡(How to fix) Fix Importing torch before QApplication on macOS prevents Qt from discovering cocoa platform plugin (inverse of #11326) [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
pytorch/pytorch#178841Fetched 2026-04-08 01:52:01
View on GitHub
Comments
0
Participants
1
Timeline
75
Reactions
0
Participants
Timeline (top)
mentioned ×33subscribed ×33labeled ×8unlabeled ×1

Error Message

This is the inverse of #11326 (which reported importing torch after QApplication crashed torch's JIT parser). That bug was fixed in modern PyTorch, but anyone searching for this error who finds #11326 will try the exact wrong fix — importing torch earlier — which triggers this bug.

Root Cause

qt.qpa.plugin: Could not find the Qt platform plugin "cocoa" in ""
This application failed to start because no Qt platform plugin could be initialized.

Fix Action

Fix / Workaround

chflags fixes it regardless of import order. The env-var-only workaround breaks when torch is imported first.

Code Example

qt.qpa.plugin: Could not find the Qt platform plugin "cocoa" in ""
This application failed to start because no Qt platform plugin could be initialized.

---

qt.qpa.plugin: Could not find the Qt platform plugin "cocoa" in "/path/to/PyQt6/Qt6/plugins/platforms"
Available platform plugins are: offscreen.

---

# Process 1:
chflags nohidden libqcocoa.dylib && stat -f %f libqcocoa.dylib
# Output: 64 (no UF_HIDDEN)

# Process 2 (new terminal):
stat -f %f libqcocoa.dylib
# Output: 32832 (UF_HIDDEN is back)

---

no torch    torch first
chflags + env var         SUCCESS     SUCCESS
chflags only              SUCCESS     SUCCESS
env var only              SUCCESS     FAIL ← torch involved HERE
nothing                   FAIL        FAIL

---

# crash.py — demonstrates the failure
import os, sys

os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = os.path.join(
    os.path.dirname(__import__('PyQt6').__file__),
    'Qt6', 'plugins', 'platforms'
)

import torch                                    # ← Causes the failure
from PyQt6.QtWidgets import QApplication
app = QApplication(sys.argv)                    # Fatal: cocoa not found

---

# works.py — demonstrates the fix
import os, sys, subprocess

qt_dir = os.path.join(
    os.path.dirname(__import__('PyQt6').__file__),
    'Qt6', 'plugins'
)
subprocess.run(['chflags', '-R', 'nohidden', qt_dir], capture_output=True)

import torch                                    # ← Safe after chflags
from PyQt6.QtWidgets import QApplication
app = QApplication(sys.argv)                    # Works
print("Success!")

---

import os, sys, subprocess

# 1. Clear UF_HIDDEN flags (must happen in same process, before Qt init)
qt_plugin_dir = os.path.join(
    os.path.dirname(__import__('PyQt6').__file__),
    'Qt6', 'plugins'
)
subprocess.run(['chflags', '-R', 'nohidden', qt_plugin_dir], capture_output=True)

# 2. Set env var as backup
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = os.path.join(
    qt_plugin_dir, 'platforms'
)

# 3. Create QApplication BEFORE any torch/ML imports
from PyQt6.QtWidgets import QApplication
app = QApplication(sys.argv)

# 4. NOW safe to import torch and dependent packages
import torch
from sentence_transformers import SentenceTransformer

---

from __future__ import annotations  # Defers annotation evaluation
from PyQt6.QtWidgets import QApplication, QMainWindow

class MyWindow(QMainWindow):
    model: SentenceTransformer  # String annotation, not evaluated at import

def main():
    app = QApplication(sys.argv)
    global SentenceTransformer
    from sentence_transformers import SentenceTransformer
    # ...
RAW_BUFFERClick to expand / collapse

🐛 Describe the bug

On macOS with Apple Silicon, importing torch before creating a QApplication prevents Qt6 from discovering the cocoa platform plugin. The application crashes with:

qt.qpa.plugin: Could not find the Qt platform plugin "cocoa" in ""
This application failed to start because no Qt platform plugin could be initialized.

Or, if QT_QPA_PLATFORM_PLUGIN_PATH is set:

qt.qpa.plugin: Could not find the Qt platform plugin "cocoa" in "/path/to/PyQt6/Qt6/plugins/platforms"
Available platform plugins are: offscreen.

Note: "Could not find" — not "Could not load." Qt sees the directory and discovers libqoffscreen.dylib and libqminimal.dylib, but not libqcocoa.dylib.

This is the inverse of #11326 (which reported importing torch after QApplication crashed torch's JIT parser). That bug was fixed in modern PyTorch, but anyone searching for this error who finds #11326 will try the exact wrong fix — importing torch earlier — which triggers this bug.

Root Cause: Two Independent Bugs

Bug 1 (Primary): UF_HIDDEN file flags on PyQt6 plugin dylibs

PyQt6-Qt6 (installed via pip) carries a com.apple.provenance extended attribute. On macOS, this causes the OS to assert UF_HIDDEN flags on the installed dylibs, including libqcocoa.dylib. Qt6's QFactoryLoader uses QDirListing without IncludeHidden, so hidden dylibs are invisible to the plugin scanner — even though the file is physically present and loadable via ctypes.CDLL().

This bug crashes PyQt6 with or without torch. A vanilla PyQt6 script on a fresh pip install can hit this.

The flags re-assert across process boundaries. Running chflags nohidden in one process clears the flag, but a new process sees UF_HIDDEN again. This was confirmed with a two-step test:

# Process 1:
chflags nohidden libqcocoa.dylib && stat -f %f libqcocoa.dylib
# Output: 64 (no UF_HIDDEN)

# Process 2 (new terminal):
stat -f %f libqcocoa.dylib
# Output: 32832 (UF_HIDDEN is back)

Therefore chflags must run in the same process before Qt initialization, every time.

Bug 2 (Secondary): torch C++ runtime pollution

Importing torch loads libtorch_cpu.dylib and related C++ shared libraries, registering 266 Objective-C classes (all MPSGraph* and _ANE*). While torch doesn't touch NSApplication or AppKit directly, its C++ runtime initialization interferes with Qt6's fallback plugin enumeration path.

This bug only matters when Bug 1's fix is incomplete — specifically, when using only QT_QPA_PLATFORM_PLUGIN_PATH without clearing hidden flags.

2×2 Test Matrix

All combinations tested as independent Python processes:

                          no torch    torch first
chflags + env var         SUCCESS     SUCCESS
chflags only              SUCCESS     SUCCESS
env var only              SUCCESS     FAIL ← torch involved HERE
nothing                   FAIL        FAIL

chflags fixes it regardless of import order. The env-var-only workaround breaks when torch is imported first.

Minimal Reproduction

# crash.py — demonstrates the failure
import os, sys

os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = os.path.join(
    os.path.dirname(__import__('PyQt6').__file__),
    'Qt6', 'plugins', 'platforms'
)

import torch                                    # ← Causes the failure
from PyQt6.QtWidgets import QApplication
app = QApplication(sys.argv)                    # Fatal: cocoa not found
# works.py — demonstrates the fix
import os, sys, subprocess

qt_dir = os.path.join(
    os.path.dirname(__import__('PyQt6').__file__),
    'Qt6', 'plugins'
)
subprocess.run(['chflags', '-R', 'nohidden', qt_dir], capture_output=True)

import torch                                    # ← Safe after chflags
from PyQt6.QtWidgets import QApplication
app = QApplication(sys.argv)                    # Works
print("Success!")

The Fix

Belt-and-suspenders (recommended)

Clear hidden flags AND set env var AND create QApplication before torch:

import os, sys, subprocess

# 1. Clear UF_HIDDEN flags (must happen in same process, before Qt init)
qt_plugin_dir = os.path.join(
    os.path.dirname(__import__('PyQt6').__file__),
    'Qt6', 'plugins'
)
subprocess.run(['chflags', '-R', 'nohidden', qt_plugin_dir], capture_output=True)

# 2. Set env var as backup
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = os.path.join(
    qt_plugin_dir, 'platforms'
)

# 3. Create QApplication BEFORE any torch/ML imports
from PyQt6.QtWidgets import QApplication
app = QApplication(sys.argv)

# 4. NOW safe to import torch and dependent packages
import torch
from sentence_transformers import SentenceTransformer

Cost: ~5ms at startup. The chflags call is idempotent.

For deferred ML imports with type annotations

from __future__ import annotations  # Defers annotation evaluation
from PyQt6.QtWidgets import QApplication, QMainWindow

class MyWindow(QMainWindow):
    model: SentenceTransformer  # String annotation, not evaluated at import

def main():
    app = QApplication(sys.argv)
    global SentenceTransformer
    from sentence_transformers import SentenceTransformer
    # ...

Broader Impact: All Qt Plugin Categories Affected

The UF_HIDDEN bug affects ALL Qt plugin directories, not just platforms/. Any Qt functionality that relies on plugin discovery can silently break:

Plugin categoryWhat breaksFallback
platforms/libqcocoa.dylibApp won't start (fatal)None — must fix
imageformats/libqjpeg.dylib etc.QPixmap can't load JPEG/TIFF/WebP/HEICPillow → QImage
tls/libqopensslbackend.dylibQNetwork HTTPS failsrequests/urllib3
sqldrivers/libqsqlite.dylibQSqlDatabase can't open SQLitesqlite3 stdlib
multimedia/libffmpegmediaplugin.dylibQMediaPlayer brokensounddevice/subprocess

The chflags -R nohidden on the entire plugins directory fixes all categories at once.

What We Verified

  1. The dylib is loadable. ctypes.CDLL("libqcocoa.dylib") succeeds before and after importing torch.
  2. torch registers 266 ObjC classes. All MPSGraph* and _ANE*. Does NOT touch NSApplication or AppKit.
  3. os.listdir() is not affected. Python sees all files. Only Qt's QDirListing respects UF_HIDDEN.
  4. QT_DEBUG_PLUGINS=1 confirms the scanner sees the directory but reports cocoa as not found while finding offscreen and minimal.
  5. Confirmed on macOS for 1 month in production use (application combining PyQt6, torch, sentence-transformers, and HuggingFace transformers).

Packages That Trigger Bug 2

Any package that transitively imports torch:

  • torch, torchvision, torchaudio
  • sentence-transformers
  • transformers (HuggingFace)
  • faster-whisper
  • Anything using torch.hub

Packages that do NOT trigger Bug 2 (safe before QApplication):

  • numpy, scipy, mlx, mlx-lm, Pillow, opencv-python

Versions

  • macOS 15.7.4 (Sequoia), Apple M2 Max, 32GB
  • Python 3.11.14 (Homebrew)
  • PyQt6 6.10.2 / Qt 6.10.0
  • torch 2.10.0
  • sentence-transformers 5.2.2

Not yet tested on Intel Mac, PySide6, or PyQt5.

cc

Related: #11326 (the inverse — importing torch after QApplication, fixed in modern torch)

Discovered while building Goose, a voice-activated radiology image retrieval system combining PyQt6 + torch + sentence-transformers on macOS Apple Silicon.

cc @malfet @aditvenk @snadampal @milpuz01 @aditew01 @nikhil-arm @fadara01 @nWEIdia @kulinseth @DenisVieriu97 @jhavukainen

extent analysis

Fix Plan

To fix the issue, follow these steps:

  • Clear the UF_HIDDEN flags on the PyQt6 plugin dylibs using chflags.
  • Set the QT_QPA_PLATFORM_PLUGIN_PATH environment variable as a backup.
  • Create a QApplication instance before importing torch or any dependent packages.

Code Changes

import os
import sys
import subprocess

# Clear UF_HIDDEN flags
qt_plugin_dir = os.path.join(
    os.path.dirname(__import__('PyQt6').__file__),
    'Qt6', 'plugins'
)
subprocess.run(['chflags', '-R', 'nohidden', qt_plugin_dir], capture_output=True)

# Set env var as backup
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = os.path.join(
    qt_plugin_dir, 'platforms'
)

# Create QApplication before importing torch
from PyQt6.QtWidgets import QApplication
app = QApplication(sys.argv)

# Now safe to import torch and dependent packages
import torch
from sentence_transformers import SentenceTransformer

Verification

To verify that the fix worked, run your application and check that it starts without crashing. You can also use the QT_DEBUG_PLUGINS=1 environment variable to enable plugin debugging and confirm that the cocoa plugin is being loaded correctly.

Extra Tips

  • The chflags call is idempotent, so it's safe to run it every time your application starts.
  • This fix affects all Qt plugin categories, not just platforms/. If you're using other Qt plugins, you may need to clear the UF_HIDDEN flags on those directories as well.
  • If you're using type annotations, you can defer the evaluation of annotations by using the from __future__ import annotations statement. This allows you to import torch and dependent packages after creating a QApplication instance.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING