Python "sys.path.insert" Hack Breaks Imports in CI
Manually inserting a relative path into sys.path works only when the process runs from the directory you assumed. In CI - different cwd, different layout - the inserted path resolves wrong and the import fails or picks up the wrong module.
What this error means
A module using sys.path.insert(0, "../lib") or sys.path.append(os.path.dirname(__file__) + "/..") imports fine locally but raises ModuleNotFoundError in CI, or worse, shadows a real package with a stale local copy.
sys.path.insert(0, "../shared")
import shared_utils
# CI runs from repo root, not the script dir:
ModuleNotFoundError: No module named 'shared_utils'Common causes
Relative path resolved against the wrong cwd
A relative sys.path.insert is resolved against the current working directory, which CI sets differently than your local shell, so it points at a nonexistent directory.
Path manipulation shadowing real packages
Inserting a directory at the front of sys.path can shadow an installed package with a local file, causing subtle import-version mismatches.
How to fix it
Replace the hack with a real package install
Make the shared code a proper package and install it editable, eliminating path manipulation entirely.
pip install -e ./shared
# then just:
import shared_utilsIf unavoidable, anchor to the file, not the cwd
Build an absolute path from __file__ so it does not depend on the working directory.
import sys, pathlib
ROOT = pathlib.Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "shared"))How to prevent it
- Prefer packaging + editable installs over
sys.pathmanipulation. - When you must manipulate the path, anchor to
__file__, not the cwd. - Avoid front-inserting paths that can shadow installed packages.