Fixing PyQGIS Module Import Errors
ModuleNotFoundError: No module named 'qgis' and ImportError: DLL load failed occur when your Python interpreter runs outside QGIS's managed environment. Fixing these errors requires either injecting QGIS library paths at runtime or executing your script through the QGIS-bundled Python executable.
Quick Fix: Manual Path Injection
When running scripts externally (VS Code, PyCharm, standalone terminal), inject QGIS paths before any qgis imports. Place this block at the top of your script:
import sys
import os
# Update to match your exact QGIS installation
QGIS_PREFIX = r"C:\Program Files\QGIS 3.44\apps\qgis" # Windows Standalone
# QGIS_PREFIX = "/Applications/QGIS.app/Contents/MacOS" # macOS
# QGIS_PREFIX = "/usr" # Linux (Debian/Ubuntu)
# Inject QGIS Python paths (order matters)
sys.path.insert(0, os.path.join(QGIS_PREFIX, "python"))
sys.path.insert(0, os.path.join(QGIS_PREFIX, "python", "plugins"))
# Set mandatory environment variables
os.environ["QGIS_PREFIX_PATH"] = QGIS_PREFIX
os.environ["PATH"] = os.path.join(QGIS_PREFIX, "bin") + os.pathsep + os.environ.get("PATH", "")
# Initialize QGIS application context
from qgis.core import QgsApplication
QgsApplication.setPrefixPath(QGIS_PREFIX, True)
qgs = QgsApplication([], False)
qgs.initQgis()
print("PyQGIS environment loaded successfully.")
Note: PYTHONHOME is intentionally omitted. Setting it in external environments frequently breaks virtual environments and triggers silent crashes.
Critical Compatibility Rules
- Python Version Alignment: PyQGIS bindings are compiled against a specific Python ABI. QGIS 3.34 and later (including the 3.44 LTR) ship with Python 3.12, while the older 3.28 LTR shipped with Python 3.9. Running an external interpreter of a different minor version against your QGIS install will fail with
ImportError. Always match your external interpreter to the QGIS release. - OS Path Variations: Windows standalone installs use
apps\qgis\python. OSGeo4W requiresC:\OSGeo4W\apps\qgis-ltr\python. macOS bundles binaries inside.app/Contents/MacOS. Linux package managers typically handle symlinks automatically, making manual injection unnecessary unless using isolatedvenvenvironments. - Architecture Mismatch: Modern PyQGIS is strictly 64-bit. Loading it with a 32-bit Python interpreter will fail on
QgsApplicationinitialization. - IDE Isolation: PyCharm and VS Code often activate isolated virtual environments that strip inherited system paths. If your IDE configuration feels opaque, reviewing PyQGIS Fundamentals & Environment Setup will help you correctly map interpreter inheritance and site-packages.
Fallbacks When Path Injection Fails
If sys.path injection throws ImportError: cannot import name 'QgsApplication' or crashes, switch to these proven alternatives:
- Execute via QGIS Python Wrapper
Bypass external interpreters by calling the bundled executable directly:
- Windows:
"C:\Program Files\QGIS 3.44\bin\python-qgis.bat" your_script.py - macOS:
/Applications/QGIS.app/Contents/MacOS/bin/python3 your_script.py - Linux:
python3 your_script.pyafter sourcing the QGIS environment shell script
- Windows:
- Run Inside the QGIS Python Console
Open QGIS → Plugins → Python Console. Paste your logic or run
exec(open('your_script.py').read()). The console auto-initializesQgsApplicationand loads allqgis.*namespaces. - Remove Conflicting PyPI Packages
Run
pip list | grep qgis(macOS/Linux) orpip list | findstr qgis(Windows). If you see aqgispackage, uninstall it immediately:pip uninstall qgis. Official PyQGIS bindings are never distributed via PyPI; the PyPIqgispackage is a documentation stub that shadows the correct libraries. - Verify Native Dependency Chains
PyQGIS relies on compiled C++ libraries (GDAL, PROJ, Qt).
DLL load failed while importing _coreusually indicates missing Visual C++ Redistributables (Windows) or mismatched GDAL binaries. Repair your QGIS installation or run the OSGeo4W installer in repair mode to restore native dependencies.
For persistent runtime crashes or silent failures during plugin execution, structured logging and step-through inspection are essential. Consult Debugging PyQGIS Scripts to isolate stack traces and validate environment states before deploying to production pipelines.
Frequently Asked Questions
Why does import qgis fail outside QGIS but work fine in the Python Console?
The QGIS Python Console runs inside the application, which has already set QGIS_PREFIX_PATH, configured PATH, and added the bundled Python libraries to sys.path. An external interpreter inherits none of that, so you must inject those paths manually before importing any qgis module.
What does ImportError: DLL load failed while importing _core actually mean?
It means Python found the qgis package but could not load its compiled C++ dependencies (GDAL, PROJ, Qt). On Windows this is usually a missing QGIS bin directory on PATH or absent Visual C++ Redistributables; repairing the QGIS install via the OSGeo4W installer often resolves it.
Do I need to match my external Python version to QGIS exactly?
You must match the minor version, because the bindings are compiled against a specific Python ABI. QGIS 3.34 and later (including 3.44 LTR) ship Python 3.12, while QGIS 3.28 shipped Python 3.9, so a 3.11 interpreter will raise ImportError against a 3.12 QGIS. Patch versions within the same minor release are fine.
Should I install the qgis package from PyPI to fix the import?
No. The PyPI qgis package is a documentation stub that shadows the real bindings and makes the problem worse. If pip list shows a qgis package in your environment, run pip uninstall qgis and rely on QGIS's bundled libraries via path injection or --system-site-packages.
Why is PYTHONHOME deliberately left unset in the fix?
Setting PYTHONHOME forces the interpreter to look for its standard library in the QGIS prefix, which breaks virtual environments and can trigger silent crashes. Setting only QGIS_PREFIX_PATH, PATH, and sys.path is enough to load the bindings without disturbing the interpreter's own runtime.