Run PyQt5 in Ubuntu

2026 maintenance note: The complete 2019 body—including its xcb error, personal fix claim, and image reference—is preserved in a dated archive near the end, with only trailing whitespace normalized. It does not identify the Ubuntu release, Python/PyQt/Qt versions, missing library, or installed package, so it cannot support one universal fix. The maintained guide below diagnoses the active interpreter, Qt installation, display session, and exact loader failure before changing packages.

Choose one installation route

PyQt5 can come from Ubuntu packages or Riverbank’s PyPI wheels. Both are valid, but the interpreter used to install and run the application must match. Record python --version, the installation command, and the resolved PyQt and Qt versions.

Ubuntu package with system Python

Ubuntu publishes python3-pyqt5 in the Universe component for supported releases:

sudo apt update
sudo apt install python3-pyqt5
python3 -c 'from PyQt5.QtCore import PYQT_VERSION_STR, QT_VERSION_STR; print("PyQt", PYQT_VERSION_STR, "Qt", QT_VERSION_STR)'

This route uses Ubuntu’s Python and Qt packaging. If APT cannot find the package, check that the correct repositories for the installed Ubuntu release are enabled; do not add a repository copied from a different release.

Project virtual environment with Riverbank wheels

For a project-isolated environment:

sudo apt update
sudo apt install python3-venv
python3 -m venv .venv
. .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install PyQt5
python -c 'from PyQt5.QtCore import PYQT_VERSION_STR, QT_VERSION_STR; print("PyQt", PYQT_VERSION_STR, "Qt", QT_VERSION_STR)'

Riverbank states that PyQt5 wheels install their corresponding Qt libraries. They still rely on operating-system facilities such as the display server and platform-plugin runtime libraries. While the environment is active, use its python; do not install with one interpreter and launch with another. Avoid sudo pip, which crosses the system/package-manager boundary.

Run a minimal, testable application

Save this as hello_pyqt5.py:

import sys

from PyQt5.QtCore import PYQT_VERSION_STR, QT_VERSION_STR, QTimer
from PyQt5.QtWidgets import QApplication, QLabel


app = QApplication(sys.argv)
label = QLabel(f"PyQt {PYQT_VERSION_STR} / Qt {QT_VERSION_STR}")
label.resize(320, 80)
label.show()

if "--smoke-test" in sys.argv:
    QTimer.singleShot(0, app.quit)

raise SystemExit(app.exec_())

Check Python syntax, then launch it from a normal Ubuntu desktop terminal:

python3 -m py_compile hello_pyqt5.py
python3 hello_pyqt5.py

Inside the virtual environment, replace python3 with python. A visible window displaying the PyQt and Qt versions is the expected desktop result. The --smoke-test switch is reserved for automated display tests later in this guide.

What the xcb error does and does not prove

The historical error was:

qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized.

2019 Qt xcb platform-plugin error screenshot

The screenshot is historical evidence of the error class, not evidence for a particular missing Ubuntu package.

Qt uses a QPA platform plugin to connect GUI code to the window system. On X11, that plugin is xcb. “Found” only means Qt located a candidate plugin file; loading or initializing can still fail because a shared library is absent, the plugin and Qt libraries are incompatible, the plugin path was overridden, or no usable display is available.

Do not begin by installing a random list of libxcb packages. First determine which of those failure classes applies.

1. Confirm the interpreter and Qt tree

Run diagnostics with the exact interpreter that fails:

command -v python3
python3 --version
python3 - <<'PY'
import PyQt5
from PyQt5.QtCore import PYQT_VERSION_STR, QT_VERSION_STR, QLibraryInfo

print("PyQt package:", PyQt5.__file__)
print("PyQt version:", PYQT_VERSION_STR)
print("Qt version:", QT_VERSION_STR)
print("Qt plugins:", QLibraryInfo.location(QLibraryInfo.PluginsPath))
PY

In a virtual environment, use python in every line. If PyQt5.__file__ and the plugin directory point into unexpected installations, stop and correct the interpreter or environment instead of copying plugin files between Qt trees.

Qt warns that a global QT_PLUGIN_PATH can interfere with other Qt installations. Inspect overrides:

env | grep -E '^QT_(PLUGIN_PATH|QPA_PLATFORM_PLUGIN_PATH|QPA_PLATFORM)=' || true

As a diagnostic, retry without the two plugin-path overrides:

env -u QT_PLUGIN_PATH -u QT_QPA_PLATFORM_PLUGIN_PATH python3 hello_pyqt5.py

If that works, remove the stale override from the environment configuration rather than replacing it with another hard-coded plugin path.

2. Confirm that a display exists

Inspect the session without modifying access control:

printf 'DISPLAY=%s\nWAYLAND_DISPLAY=%s\nXDG_SESSION_TYPE=%s\n' \
  "${DISPLAY-}" "${WAYLAND_DISPLAY-}" "${XDG_SESSION_TYPE-}"

On a local Ubuntu desktop, the session normally provides a usable display connection. In a plain SSH shell, container, service, or CI job, neither display variable may be usable. Installing another XCB library cannot create a display server or its authentication.

Do not use xhost + as a shortcut: it weakens X server access control. Use a properly authenticated desktop/remote-display session or one of the isolated headless test routes below.

3. Ask Qt why the plugin failed

Qt documents QT_DEBUG_PLUGINS for detailed plugin-loading diagnostics:

QT_DEBUG_PLUGINS=1 python3 hello_pyqt5.py 2>qt-plugin-debug.log

Read the first loader error around libqxcb.so, not just the final generic message:

grep -E 'libqxcb|not found|cannot open|undefined symbol|version' qt-plugin-debug.log

The log can contain local paths and environment details. Keep it private and remove or redact it before sharing.

4. Check the installed xcb plugin’s dependencies

Print the platform-plugin directory with the same interpreter:

qt_plugin_dir="$(python3 -c 'from PyQt5.QtCore import QLibraryInfo; print(QLibraryInfo.location(QLibraryInfo.PluginsPath))')"
find "$qt_plugin_dir/platforms" -maxdepth 1 -name 'libqxcb.so' -print

For a trusted plugin installed by Ubuntu or the selected virtual environment, inspect unresolved libraries:

ldd "$qt_plugin_dir/platforms/libqxcb.so" | grep 'not found' || true

If nothing is missing, do not install more XCB packages. Return to the debug log and look for an incompatible symbol/version, unexpected plugin tree, or display connection failure.

If a specific shared object is missing, map that exact filename to the package for the current Ubuntu release:

sudo apt update
sudo apt install apt-file
sudo apt-file update
apt-file search libxcb-xinerama.so.0

For example, install libxcb-xinerama0 only when the diagnostics name libxcb-xinerama.so.0 and the current release’s package index maps it to that package. Package names and dependencies can change by release and architecture. Re-run ldd, the smoke test, and the real application after installing the evidenced package.

5. Separate desktop, offscreen, and virtual-X tests

These tests answer different questions.

An offscreen Qt smoke test constructs the widgets without using xcb:

QT_QPA_PLATFORM=offscreen python3 hello_pyqt5.py --smoke-test

Success proves that Python can import PyQt5 and construct the example with the available offscreen plugin. It does not prove that xcb or the desktop display works.

To exercise the X11/xcb path in headless CI, use an isolated virtual X server:

sudo apt update
sudo apt install xvfb xauth
xvfb-run -a python3 hello_pyqt5.py --smoke-test

xvfb-run creates X authority data, launches Xvfb, runs the command, and cleans up when it exits. A successful Xvfb test plus a failed desktop launch points toward the real desktop session, authorization, or environment. A successful offscreen test plus a failed Xvfb test keeps the focus on xcb and its X11 dependencies.

Do not force QT_QPA_PLATFORM=xcb globally on a Wayland desktop. Platform availability depends on the installed Qt build and session. Leave automatic platform selection alone when it works; use a one-command override only as a documented diagnostic.

6. Read the failure signature before choosing an action

Evidence Likely boundary Next action
ModuleNotFoundError: No module named 'PyQt5' Wrong interpreter or PyQt5 not installed there Select the intended APT or virtual-environment route and verify with that interpreter
libNAME.so... => not found or “cannot open shared object file” Missing runtime library Use apt-file search for the exact filename, install the mapped current-release package, and rerun diagnostics
“undefined symbol”, incompatible Qt version, or unexpected plugin path Mixed Qt/plugin trees Remove stale path overrides and rebuild one coherent installation; do not copy libqxcb.so manually
“could not connect to display” or empty/unusable display variables Session/display boundary Use the logged-in desktop, configured remote display, offscreen smoke test, or Xvfb as appropriate
Offscreen passes; Xvfb fails X11/xcb loading or initialization Inspect QT_DEBUG_PLUGINS and ldd results
Xvfb passes; desktop fails Desktop session, authorization, or environment Compare display variables and Qt overrides between the two sessions
All minimal tests pass; the real app fails Application-specific import, plugin, rendering, or startup code Reduce the application incrementally and capture the first new error

7. Avoid fixes that hide the cause

  • Do not install every package whose name begins with libxcb; install the package justified by a missing filename.
  • Do not copy platform plugins between system Qt, a wheel-provided Qt, Conda, an IDE, or another application.
  • Do not set QT_PLUGIN_PATH, QT_QPA_PLATFORM_PLUGIN_PATH, or LD_LIBRARY_PATH globally to a path copied from a tutorial.
  • Do not run the application with sudo to reach another user’s display or package installation.
  • Do not use sudo pip to modify Ubuntu’s Python environment.
  • Do not treat QT_QPA_PLATFORM=offscreen as a fix for an interactive desktop application; it deliberately renders without a visible desktop window.
  • Do not publish plugin debug logs without reviewing local paths and environment data.

A reproducible verification record

Record these results with the issue or project:

  • Ubuntu release and architecture from lsb_release -ds and dpkg --print-architecture;
  • exact Python executable and version;
  • PyQt and Qt versions and PyQt5.__file__;
  • installation route and locked project dependencies where applicable;
  • DISPLAY, WAYLAND_DISPLAY, and XDG_SESSION_TYPE presence, without sharing session secrets;
  • Qt plugin directory and the first relevant QT_DEBUG_PLUGINS loader error;
  • unresolved ldd entries and the Ubuntu package mapping used;
  • syntax, offscreen, Xvfb, and real-desktop test results;
  • the change made and how it was rolled back.

That record distinguishes a reproducible fix from “installed something XCB-related and it worked.”

2019 original export (source archive)

Archive boundary: The text inside the block below is the complete body from out/posts/2019-04-23-run-pyqt5-in-ubuntu-1898/index.md, exported from post 1898 and dated 23 April 2019. Its wording, punctuation, curly quotes, image path, and personal claim are unchanged; trailing whitespace is normalized. Do not execute it as a current repair procedure.


qt.qpa.plugin: Could not load the Qt platform plugin “xcb” in “” even though it was found. This application failed to start because no Qt platform plugin could be initialized.

I accidentally installed the xcb plugin and the problem solved.

![](images/image-1.png)

Primary and official references

Leave a Reply