Fixing Poetry Virtualenv Path After Moving a Project Directory
The Problem
After moving a Python project from one directory to another:
/Users/you/projects/my-python-app
→
/Users/you/new-projects/my-python-app
Poetry kept reporting the old virtualenv path:
❯ poetry env info
Virtualenv
Python: 3.11.11
Path: /Users/you/projects/my-python-app/.venv
Valid: False
Despite running poetry env remove, poetry env use, and even deleting .venv entirely, the old path persisted.
The Investigation
Red Herrings
Several things were checked but turned out not to be the cause:
- Poetry cache directories (
~/Library/Caches/pypoetry/) - contained package artifacts, not virtualenv paths - Poetry config files (
~/Library/Application Support/pypoetry/config.toml) - correctly setvirtualenvs.in-project = true - Project files (
pyproject.toml,poetry.lock) - no hardcoded paths .venv/pyvenv.cfg- did not contain the old path- Poetry hash-based caching - Poetry uses SHA256 hashes of project paths, but no cached hash files were found
The Real Culprit
The issue was found by checking environment variables:
❯ env | grep -i virtual
VIRTUAL_ENV=/Users/you/projects/my-python-app/.venv
The VIRTUAL_ENV environment variable was set to the old path!
Root Cause
The project used direnv with a .envrc file that sources the virtualenv:
# .envrc
dotenv
source .venv/bin/activate
When the project was moved:
- The old
.venvdirectory was moved along with the project - The
.venv/bin/activatescript contained a hardcodedVIRTUAL_ENVpath pointing to the old location - direnv cached this environment when first entering the directory
- Even after recreating
.venv(with the correct path in its activate script), direnv continued using its cached environment
Poetry reads the VIRTUAL_ENV environment variable to determine the current virtualenv, so it kept reporting the old (now invalid) path.
The Solution
After recreating the .venv directory (which Poetry did correctly):
rm -rf .venv && poetry install
The fix was simply to reload direnv to pick up the new activate script:
direnv reload
Or leave and re-enter the directory:
cd .. && cd -
Key Takeaways
-
Poetry’s
env inforeflectsVIRTUAL_ENV- If this environment variable is set, Poetry reports it rather than discovering the virtualenv fresh. -
direnv caches environment state - When you source a script via direnv, the resulting environment is cached. Changes to the underlying script require
direnv reload. -
Virtualenv activate scripts contain hardcoded paths - The
VIRTUAL_ENVvariable in.venv/bin/activateis set to an absolute path at creation time. Moving the directory breaks this. -
The fix is often simpler than expected - After extensive investigation of Poetry internals, the solution was a simple
direnv reload.
Prevention
When moving a Python project that uses Poetry + direnv:
- Delete the old
.venvbefore or after moving - Run
poetry installto create a fresh virtualenv - Run
direnv reloadto refresh the cached environment
Or more simply: after moving any project with direnv, always run direnv reload.