Skip to content

Fix: uv Not Working — Command Not Found, Python Version Error, and Lock File Conflicts

FixDevs ·

Quick Answer

How to fix uv errors — uv command not found after install, no Python interpreter found, uv run vs activate confusion, uv.lock merge conflicts, uv pip vs uv add, migrating from pip and Poetry, and workspace resolution failures.

The Error

You install uv and the command isn’t found:

uv: command not found

Or uv can’t find the Python version your project needs:

error: No interpreter found for Python 3.11 in virtual environments,
managed installations, or search path

Or you run uv sync and the packages vanish when you open a new terminal:

uv sync
python -c "import requests"  # Works
# Open new terminal
python -c "import requests"  # ModuleNotFoundError

Or merging two feature branches breaks the lock file:

error: Failed to parse `uv.lock`: TOML parse error at line 47

uv is fast and opinionated — it manages Python versions, virtual environments, and dependencies together. Most issues come from expecting pip or Poetry behavior from a tool that works differently by design.

Why This Happens

uv separates concerns sharply: uv add manages project dependencies (modifying pyproject.toml and uv.lock), uv pip manages environments directly (like pip), and uv run handles execution with automatic environment sync. Using the wrong command for the wrong context is the source of most confusion.

Python version management is also built in — uv downloads and manages its own Python installations independently of whatever Python is on your system. This is intentional and usually works seamlessly, but requires understanding when it applies.

Fix 1: uv: command not found — Installation and PATH

After running the install script, uv goes to ~/.local/bin/ but that directory may not be in your shell’s PATH.

Install uv:

# macOS / Linux (standalone installer — recommended)
curl -LsSf https://astral.sh/uv/install.sh | sh

# macOS (Homebrew)
brew install uv

# Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

# Windows (winget)
winget install --id=astral-sh.uv -e

If uv still isn’t found after installing, the issue is PATH. The installer adds a line to your shell config, but that line only takes effect in new terminal sessions.

Either open a new terminal, or source your config manually:

# Bash
source ~/.bashrc

# Zsh
source ~/.zshrc

If you’re in a shell that doesn’t source either of those (e.g., a non-login shell in some CI environments), add the path explicitly:

export PATH="$HOME/.local/bin:$PATH"

To make it permanent, add that line to your ~/.bashrc or ~/.zshrc.

Windows: uv installs to %USERPROFILE%\.local\bin. Add this to your system PATH via System Properties → Advanced → Environment Variables, or in PowerShell:

$env:PATH = "$env:USERPROFILE\.local\bin;$env:PATH"

Verify the install worked:

uv --version
# uv 0.6.x (yyyy-mm-dd)

Fix 2: Python Version Not Found

error: No interpreter found for Python 3.12 in virtual environments,
managed installations, or search path

uv manages its own Python installations separately from any Python you’ve installed through Homebrew, pyenv, or the system package manager. If a project requires Python 3.12 and uv hasn’t downloaded it yet, you get this error.

Install the required Python version through uv:

uv python install 3.12

# Install multiple versions at once
uv python install 3.11 3.12 3.13

# List all available versions
uv python list

# List only installed versions
uv python list --only-installed

Pin the Python version for your project by creating a .python-version file:

uv python pin 3.12
# Creates .python-version containing "3.12"

This tells uv which version to use for this project. Commit the .python-version file so everyone on the team uses the same version.

If you want to use the system Python rather than uv’s managed version:

uv run --python $(which python3) script.py

# Or set it in pyproject.toml to point to a system Python
uv python pin /usr/bin/python3.12

Common cause of version conflicts: requires-python in pyproject.toml and .python-version disagreeing:

# pyproject.toml says 3.10+
[project]
requires-python = ">=3.10"
# .python-version says 3.9
3.9.18

uv enforces requires-python strictly. Fix by updating .python-version:

uv python pin 3.11   # Within the >=3.10 range

Pro Tip: uv automatically downloads missing Python versions by default. If you’re on a restricted network or an air-gapped machine, disable this with UV_PYTHON_DOWNLOADS=never to force uv to only use already-installed interpreters.

Fix 3: Packages Missing in New Terminal — uv run vs Manual Activation

This is the single most common source of confusion for developers coming from pip. uv sync creates a virtual environment in .venv/, but that environment is only active in the current shell session if you explicitly activate it.

uv sync                         # Creates .venv, installs packages
python -c "import requests"     # Works — because .venv/bin is first in PATH?
                                # No — this depends on whether you activated it

The uv way: use uv run instead of activating:

uv run python script.py
uv run pytest
uv run flask run

uv run automatically syncs the environment to the current lockfile and then executes the command. You never need to activate anything — uv handles it per-invocation.

When you do need manual activation (for interactive sessions or IDE setup):

# Create and sync the environment first
uv sync

# Activate
source .venv/bin/activate       # Linux/macOS bash/zsh
.venv\Scripts\Activate.ps1      # Windows PowerShell
.venv\Scripts\activate.bat      # Windows cmd

# Now python/pip refer to the venv
python script.py

# Deactivate when done
deactivate

For IDEs (VS Code, PyCharm): point the interpreter to .venv/bin/python (Linux/macOS) or .venv\Scripts\python.exe (Windows). The IDE will activate the environment automatically for its terminal.

Why packages disappear in a new terminal: the environment exists in .venv/ and is always there — it just isn’t active unless you activate it or use uv run. The packages didn’t go anywhere; your shell just doesn’t know to look in .venv/bin first.

Fix 4: uv.lock Conflicts After Merging Branches

uv.lock is a machine-generated file that fully specifies the dependency resolution for every supported platform. When two branches both modify dependencies independently, merging them produces a broken lock file with TOML syntax errors — it can’t be resolved manually like a regular merge conflict.

The fix: always regenerate the lock file after a merge conflict on it:

# After seeing merge conflict markers in uv.lock:
rm uv.lock          # Delete the broken file
uv lock             # Regenerate from scratch based on pyproject.toml

If both branches added different packages, pyproject.toml will also have merge conflicts. Resolve those first (they’re readable), then regenerate the lock:

# 1. Fix pyproject.toml conflicts manually
# 2. Then regenerate
uv lock

Commit the regenerated uv.lock — it should be tracked in git. Every team member running uv sync will then get a deterministic, identical environment.

For dependency version conflicts (where two packages need incompatible versions of a third package):

error: Because package-a==1.0 requires dep>=2.0 and package-b==3.0 requires dep<2.0,
we can't satisfy all constraints.

View what’s constraining the resolution:

uv lock --verbose

Try upgrading to newer versions that may have resolved the constraint:

uv lock --upgrade                    # Upgrade everything within allowed ranges
uv lock --upgrade-package package-a  # Upgrade one package specifically

If the conflict is genuine (two packages truly can’t coexist), you need to replace one of them or find a version combination that works. Run uv lock --verbose and read the resolution output to understand which package is pulling in the conflicting requirement.

Fix 5: uv pip install vs uv add — Which One to Use

uv has two distinct package management modes. Using the wrong one leads to packages that seem installed but aren’t tracked, or packages that don’t appear in the environment you expect.

uv add — use this for project development:

uv add requests           # Adds to [project.dependencies] in pyproject.toml
uv add --dev pytest       # Adds to dev dependencies
uv add "django>=4.2"      # With version constraint
uv remove requests        # Removes from pyproject.toml and uv.lock

uv add modifies pyproject.toml, updates uv.lock, and installs into the project’s .venv. This is the equivalent of poetry add — dependencies are tracked and reproducible.

uv pip install — use this for one-off installs or when working without a project:

uv pip install requests                # Installs to the active virtual environment
uv pip install -r requirements.txt    # Install from requirements file
uv pip sync requirements.txt          # Sync env to EXACTLY match requirements.txt (removes extras)

uv pip install doesn’t touch pyproject.toml. It installs directly to whatever environment is active (or to a default location if none is active). Use it for quick experimentation or for pip-style workflows without a full project structure.

Common Mistake: Running uv pip install requests in a project directory and wondering why uv sync later removes it. uv sync brings the environment in line with uv.lock, which was generated from pyproject.toml. Since requests wasn’t in pyproject.toml, uv sync removes it. Use uv add requests instead.

The mental model: uv add = “this is part of my project”, uv pip install = “put this in the environment right now”.

Fix 6: Migrating from pip / Poetry / pyenv

From pip + requirements.txt:

# Initialize a new uv project in an existing directory
uv init

# Import dependencies from requirements.txt
uv add -r requirements.txt

# Import dev dependencies
uv add --dev -r requirements-dev.txt

# Generate the lock file
uv lock

The uv.lock file replaces pip freeze > requirements.txt for reproducible installs. Other developers run uv sync instead of pip install -r requirements.txt.

From Poetry:

uv uses the same pyproject.toml format as Poetry, but the section headers differ:

# Poetry (old)
[tool.poetry.dependencies]
python = "^3.11"
requests = "^2.31"

[tool.poetry.dev-dependencies]
pytest = "^7.0"

# uv (new)
[project]
requires-python = ">=3.11"
dependencies = ["requests>=2.31"]

[project.optional-dependencies]
dev = ["pytest>=7.0"]

Migration steps:

# Remove Poetry files
rm poetry.lock

# Initialize uv (keeps pyproject.toml, just changes the format)
uv init --no-readme

# Add dependencies from the old [tool.poetry.dependencies] section
uv add requests  # Repeat for each dependency

# Add dev dependencies
uv add --dev pytest

# Sync and verify
uv sync
uv run pytest

From pyenv:

pyenv manages Python versions at the system level; uv manages them at the project level. They can coexist, but once you use uv python install, you usually don’t need pyenv for Python version management anymore:

# Check what pyenv has
pyenv versions

# Install the same version in uv
uv python install 3.11.7

# Pin for the project
uv python pin 3.11.7

# uv now uses its own 3.11.7, not pyenv's

If you want uv to use pyenv’s Python (to share a single installation), point uv python pin at the pyenv binary:

uv python pin $(pyenv which python3.11)

For package installation errors that arise during migration — like packages that fail to build from source — see Python packaging not working and pip could not build wheels.

Fix 7: Inline Script Dependencies — PEP 723 Syntax

uv supports PEP 723 inline script metadata, which lets you declare dependencies directly in a single .py file. The syntax is strict — any deviation causes a silent parse failure.

Correct format:

# /// script
# requires-python = ">=3.11"
# dependencies = [
#   "requests>=2.31",
#   "click>=8.0",
# ]
# ///

import requests
import click

@click.command()
@click.argument("url")
def fetch(url):
    print(requests.get(url).text[:200])

if __name__ == "__main__":
    fetch()

Run it:

uv run fetch.py https://example.com
# uv automatically creates an isolated env, installs deps, runs the script

Common syntax errors that silently break parsing:

# WRONG — trailing space after ///
# ///    ← space here breaks it

# WRONG — empty line without # prefix
# /// script
# dependencies = ["requests"]
#                             ← this empty line breaks it
# ///

# CORRECT — every line in the block starts with #
# /// script
# requires-python = ">=3.11"
# dependencies = [
#   "requests>=2.31",
# ]
# ///

If uv ignores your inline dependencies and says the package isn’t found, it’s almost always a whitespace issue in the block.

Add dependencies to an existing script via CLI (instead of editing manually):

uv add --script fetch.py requests click

This correctly inserts the block with proper formatting.

Lock a script’s dependencies for reproducibility:

uv lock --script fetch.py
# Creates fetch.py.lock alongside the script

Fix 8: Workspace Resolution Failures

Workspaces let you manage multiple related Python packages in one repository with a shared uv.lock. When they break, the error is usually a dependency version conflict between members or a missing pyproject.toml in a member directory.

Workspace setup (root pyproject.toml):

[tool.uv.workspace]
members = [
    "packages/api",
    "packages/worker",
    "packages/shared",
]

Each member directory needs its own pyproject.toml:

# packages/api/pyproject.toml
[project]
name = "api"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
    "fastapi>=0.110",
    "shared",          # Another workspace member
]

[tool.uv.sources]
shared = { workspace = true }  # Tells uv this is a workspace member, not PyPI

Error: workspace member not found:

error: Workspace member `packages/api` not found

Check that:

  1. The directory exists and contains a pyproject.toml
  2. The glob pattern in members matches the actual path
  3. No typos in the path string
ls packages/api/pyproject.toml   # Must exist

Error: conflicting dependency versions between members:

error: Because api requires requests==2.28.0 and worker requires requests>=2.31.0,
we can't satisfy all requirements.

All workspace members share a single lock file, so their dependencies must be jointly resolvable. Fix by aligning version constraints:

# Change from exact pins to ranges in all affected members
dependencies = ["requests>=2.28.0,<3"]  # Both members can agree on this

Run a command in a specific workspace member:

uv run --package api python -m uvicorn app:main
uv run --package worker python -m celery worker

Still Not Working?

uv sync Is Slow or Re-downloads Everything

uv caches downloaded packages in ~/.cache/uv/ (Linux/macOS) or %LOCALAPPDATA%\uv\cache (Windows). If the cache is missing or corrupted:

uv cache clean    # Clear the cache
uv sync           # Re-download (will be fast after the first time)

On CI/CD, cache the uv cache directory between runs to avoid re-downloading packages on every build:

# GitHub Actions example
- uses: actions/cache@v4
  with:
    path: ~/.cache/uv
    key: uv-${{ hashFiles('uv.lock') }}

Package Installs But import Fails

If uv add requests reports success but uv run python -c "import requests" fails, check which environment is active:

uv run python -c "import sys; print(sys.executable)"
# Should print: /path/to/your/project/.venv/bin/python

# If it prints a system Python path, uv is using the wrong interpreter
# Run from within the project directory, not a parent

uv uses the pyproject.toml in the current directory to locate the project. If you run uv run from a parent directory, it may not find the project and use a fallback environment.

Editable Installs and Package Not Found in Workspace

If a workspace member’s package code isn’t importable despite being in the workspace:

uv sync --editable    # Install workspace members as editable

Or add editable = true in the workspace source:

[tool.uv.sources]
shared = { workspace = true, editable = true }

Comparing uv with pip and Poetry

uv doesn’t replace pip entirely — uv pip is pip-compatible for environments and scripts. The project management commands (uv init, uv add, uv sync) replace Poetry and pip-tools. For understanding how requires-python and virtual environment isolation work at a deeper level, see Python virtualenv wrong Python and Python ModuleNotFoundError venv.

Build Failures for Packages with C Extensions

Some packages (numpy, cryptography, psycopg2) compile C code during installation. If compilation fails:

# Show the full build log
uv add --verbose cryptography

# Use a pre-built wheel instead of building from source
uv add --no-build-isolation cryptography

# On macOS: ensure Xcode tools are installed
xcode-select --install

Build failures during uv add are usually a missing system library or compiler, not a uv issue. The error output from the failed build contains the actual cause. See Python packaging not working for the full set of build error patterns.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles