Skip to content
Latchkey

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.

Python traceback
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.

Terminal
pip install -e ./shared
# then just:
import shared_utils

If unavoidable, anchor to the file, not the cwd

Build an absolute path from __file__ so it does not depend on the working directory.

Python
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.path manipulation.
  • When you must manipulate the path, anchor to __file__, not the cwd.
  • Avoid front-inserting paths that can shadow installed packages.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →