Cursor Python Venv Not Detected (Wrong Interpreter)

Cursor uses system Python instead of your project venv, breaking imports, linting, and agent edits. Fix the interpreter picker, venv discovery, shell PATH, and the new Python Environments panel.

You activated .venv, ran pip install -r requirements.txt, and everything works in your terminal. You open the same project in Cursor and every import lights up red. Pylance reports Import "fastapi" could not be resolved. Composer suggests pip install fastapi even though it is already installed. The status bar shows Python 3.11.7 64-bit pointing at /usr/local/bin/python3 instead of .venv/bin/python. This is a Python-extension interpreter discovery problem, not a real package install issue, and it cascades into every surface: linting, type checking, agent edits, and run-and-debug.

Fastest fix: press Cmd+Shift+P (Windows/Linux Ctrl+Shift+P), run Python: Select Interpreter, choose “Enter interpreter path…”, and paste the absolute path to .venv/bin/python (.venv\Scripts\python.exe on Windows). Then Python: Restart Language Server. That clears roughly 80% of cases. If it does not stick, work through the buckets below.

One thing changed in 2026 that trips people up: the Microsoft Python Environments extension (ms-python.vscode-python-envs) went generally available in February 2026 and is now the default environment manager for the Python extension. Interpreter selection has partly moved out of the status bar into a dedicated Python panel / tree view. If your status-bar interpreter looks right but imports still fail, the active environment in that panel may differ. See bucket 7 below.

Which bucket are you in?

Run one quick check, then jump to the matching cause.

Quick checkWhat you seeMost likely cause
Status bar / Python panel interpreterPoints at /usr/local/bin or /opt/homebrew/binCause 1: wrong interpreter cached
Python: Select Interpreter listYour venv is not listed at allCause 2 or 3: venv outside root or tool-managed
conda info --envs vs pickerEnv exists but shows as (base)Cause 4: conda not wired up
Integrated terminal echo $PATHMissing your .zshrc entriesCause 5: GUI PATH inheritance
Same window, different filesOne file resolves, another does notCause 6: multi-root mismatch
Status bar right, imports still redPython panel shows a different active envCause 7: Python Environments panel split

Common causes

Ordered by likelihood for venv detection failures.

1. Cursor picked the wrong interpreter on first open

The Python extension scans for interpreters at workspace open and caches the choice in .vscode/settings.json. If the venv was created after that first open — or under a non-standard path — the cached choice points at the system Python and never updates.

How to spot it: .vscode/settings.json has "python.defaultInterpreterPath" pointing at /usr/local/bin/python or /opt/homebrew/bin/python3 rather than .venv/bin/python.

2. Venv lives outside the workspace root

If your venv is at ~/.virtualenvs/myproj (virtualenvwrapper) or in a sibling directory, the extension’s auto-scan misses it. Only ./.venv, ./venv, ./env get auto-detected.

How to spot it: which python in the integrated terminal shows the right venv, but the status-bar interpreter does not list it as an option.

3. Poetry / PDM / Hatch / uv-managed venv

poetry (by default) and pdm store venvs in centralized caches (~/.cache/pypoetry/virtualenvs/...). Cursor’s Python extension picks them up only when the path is supplied explicitly. (uv is different: as of June 2026 uv sync and uv venv create the env at ./.venv in the project root, so uv venvs usually auto-detect; the cache holds downloaded interpreters, not the project venv.)

How to spot it: poetry env info --path returns a path that does not appear in the interpreter picker.

4. Conda environment not activated in Cursor’s launcher

Conda envs need either Anaconda Python extension support enabled or a python.condaPath setting. Without it, the env appears with the wrong base prefix and imports fail.

How to spot it: conda info --envs shows your env, but in Cursor the interpreter list shows it as (base) even when you select the project env.

5. Shell PATH differs between Cursor and terminal

Cursor inherits PATH from the parent process that launched it (Finder, Dock, Spotlight). If you depend on .zshrc/.bashrc for venv activation, those rc files never run for the GUI process.

How to spot it: Open the integrated terminal — echo $PATH is missing the entries you set in .zshrc. A fresh Terminal.app shows them fine.

6. Workspace is multi-root and the active root has no Python config

In a multi-root workspace, each folder can have its own Python interpreter. The status bar reflects whichever folder owns the active editor file — flipping between files in different roots silently swaps interpreter.

How to spot it: Imports work in one file but not in another in the same Cursor window. Status-bar interpreter changes when you click between them.

7. The Python Environments panel has a different active env

Since the Python Environments extension (ms-python.vscode-python-envs) went GA in February 2026, it became the default environment manager and now owns much of interpreter selection through its own Python tree view in the Activity Bar. The status-bar selector and this panel can disagree, especially right after upgrading, so the bar can read .venv while the panel still has the system Python set as the active environment used for analysis.

How to spot it: Open the Python panel (Activity Bar, or Cmd+Shift+P -> Python: Focus on Python View). The environment marked active there is not your .venv. If you prefer the old behavior, you can opt out with "python.useEnvironmentsExtension": false in settings, restart, and selection reverts to the status bar.

Before you start

  • Confirm the venv actually works: source .venv/bin/activate && python -c "import fastapi" succeeds from a plain terminal.
  • Note your venv location and tool (raw venv, virtualenv, poetry, pdm, uv, conda).
  • Record the current interpreter shown in the Cursor status bar — bottom right, click “Python”.
  • Capture .vscode/settings.json before edits.

Information to collect

  • Output of which python and python --version from Cursor’s integrated terminal.
  • For Poetry: poetry env info --path. For uv: uv run python -c "import sys; print(sys.executable)" (there is no uv venv --path subcommand).
  • Contents of .vscode/settings.json (Python-related keys).
  • Status-bar interpreter path (full path, not just the label).
  • The active environment in the Python panel (it can differ from the status bar).
  • Pylance “Show language server output” log: look for the Selected interpreter: line.
  • Whether Cursor was launched from Finder, terminal cursor ., or Spotlight.

Step-by-step fix

Ordered fastest to most thorough.

Step 1: Set the interpreter explicitly via the command palette

Cmd+Shift+P -> Python: Select Interpreter -> “Enter interpreter path…” and paste the absolute path:

/Users/you/proj/.venv/bin/python

On Windows the binary is .venv\Scripts\python.exe, not bin/python. This writes the choice to your workspace and triggers an analyzer restart. About 80% of cases stop here.

If you do not see the path you want in the list, click “Enter interpreter path…” -> “Find…” and browse to it.

If pasting .venv/bin/python returns An invalid Python interpreter is selected, try pointing “Find…” at the .venv folder itself rather than the binary inside it. This is a known Cursor quirk where the folder resolves but the explicit binary path does not.

If imports still show red after selecting, run Python: Restart Language Server before assuming it failed. Pylance does not always reload analysis on its own.

Step 2: Pin the interpreter in workspace settings

Open .vscode/settings.json and lock it in:

{
  "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python",
  "python.terminal.activateEnvironment": true,
  "python.analysis.extraPaths": ["${workspaceFolder}/src"]
}

Using ${workspaceFolder} keeps the path portable across machines. Commit this file so teammates inherit the choice.

Step 3: Fix PATH inheritance for GUI launches

If integrated-terminal echo $PATH is missing entries, the rc files are not loading. Two options.

Move PATH-setting lines out of .zshrc (interactive only) into .zprofile (login shells, which Cursor’s terminal uses):

# ~/.zprofile
export PATH="/opt/homebrew/bin:$HOME/.local/bin:$PATH"

Or launch Cursor from a terminal so it inherits the right environment:

cursor .

After either fix, restart Cursor entirely (not just reload window).

Step 4: For Poetry / uv / PDM, point Cursor at the managed venv

For Poetry, get the path and select it via Step 1:

poetry env info --path

The cleaner fix is to make Poetry build the venv in-project so auto-detection works without any pinning:

poetry config virtualenvs.in-project true
poetry env remove --all
poetry install

A .venv folder now appears in the workspace root.

For uv, the env already lives at ./.venv after uv sync (or uv venv), so it normally auto-detects. There is no uv venv --path subcommand; to confirm which interpreter uv uses, run:

uv run python -c "import sys; print(sys.executable)"

If you only fixed the editor but the agent still suggests pip install for installed packages, the agent spawns a fresh shell that does not inherit your activated venv. Add a .cursor/rules entry telling it to run Python through the env, for example “always use uv run for Python and tests in this project” (or poetry run). The interpreter pin fixes Pylance; the rule fixes the agent’s terminal commands.

Step 5: For Conda, install the Anaconda Python extension and set conda path

In Cursor extensions, install “Python” (Microsoft) and ensure the Conda integration is enabled. Then:

{
  "python.condaPath": "/opt/homebrew/Caskroom/miniforge/base/condabin/conda",
  "python.defaultInterpreterPath": "/opt/homebrew/Caskroom/miniforge/base/envs/myproj/bin/python"
}

Activate via Cmd+Shift+P -> Python: Select Interpreter and pick the conda env explicitly.

Step 6: For multi-root workspaces, pin per folder

Each folder in a multi-root workspace can carry its own .vscode/settings.json. Add the pin to every Python folder:

{
  "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python"
}

Now switching between files no longer flips interpreters.

Step 7: Reconcile the Python Environments panel

If the status bar reads .venv but imports stay red after a restart, the Python Environments extension may have a different active env. Open the Python panel (Activity Bar, or Cmd+Shift+P -> Python: Focus on Python View), find your .venv, and set it as the active environment for the workspace from there. If you would rather keep the pre-2026 status-bar workflow, opt out and restart:

{
  "python.useEnvironmentsExtension": false
}

Verify

  • Open a .py file from the project. Status bar shows Python 3.x.x (.venv) or your tool’s name.
  • Type import <pkg> for a package only present in the venv. No red squiggle.
  • Run python -c "import sys; print(sys.executable)" in a debug session — output matches .venv/bin/python.
  • Ask Composer to “add a fastapi route” — it should not propose pip install fastapi if it is already in requirements.txt.

Long-term prevention

  • Always create the venv before opening the project in Cursor for the first time.
  • Commit .vscode/settings.json with python.defaultInterpreterPath pinned.
  • Use poetry config virtualenvs.in-project true (or uv sync, which creates ./.venv) so the venv lives at ./.venv and gets auto-detected.
  • Put PATH-setting commands in .zprofile not .zshrc so GUI launches inherit them.
  • Add a .cursor/rules line telling the agent to run Python through the env (uv run / poetry run) so agent terminal commands match the editor interpreter.
  • Add a make setup / just setup target so new contributors get the venv at the standard path.
  • Run python -c "import sys; print(sys.prefix)" as part of pytest startup; assert it matches .venv in CI.

Common pitfalls

  • Selecting the interpreter once, then deleting and recreating the venv — the cached path now points at a non-existent binary. Re-select after rm -rf .venv && python -m venv .venv.
  • Putting python.defaultInterpreterPath in user settings instead of workspace settings — it leaks across projects.
  • Activating the venv in the integrated terminal and assuming Pylance now sees it. Pylance uses the configured interpreter, not the terminal’s active venv.
  • Trusting the status-bar label alone — it can say .venv but actually point at a stale path. Verify with python -c "import sys; print(sys.executable)".
  • Running cursor . from a terminal where the venv is already activated and getting different behavior than launching from Finder. Standardize one launch method per machine.
  • Forgetting that conda envs need an extra python.condaPath setting beyond just the interpreter pin.

FAQ

Q: Composer / the agent keeps suggesting pip install for packages already installed.

Two layers. Pylance and inline analysis read the interpreter you selected, so fixing the interpreter pin stops the red squiggles. But the agent runs terminal commands in a fresh shell that does not inherit your activated venv, so it can still miss installed packages. Add a .cursor/rules instruction to run Python through the env (uv run, poetry run, or the explicit .venv path). See also Cursor reads wrong file.

Q: The status bar shows .venv but imports are still red.

Since the Python Environments extension went GA in February 2026, the status bar and the new Python panel can disagree. Open the panel (Python: Focus on Python View) and set .venv active there, or set "python.useEnvironmentsExtension": false and restart.

Q: I changed python.defaultInterpreterPath but nothing updated.

Pylance caches the analyzer state. Cmd+Shift+P -> Python: Restart Language Server, or just reload the window.

Q: My venv is at ~/.virtualenvs/myproj. Can I keep it there?

Yes — pin the absolute path in .vscode/settings.json. But moving to ./.venv per project is simpler and more portable.

Q: Tests pass in terminal but fail under Cursor’s test explorer.

The test runner uses Cursor’s configured interpreter, not your active terminal venv. Verify the interpreter pin matches what the terminal uses.

Tags: #Cursor #Troubleshooting #Debug #AI coding