astral-sh/uv
Debugging
uv is heavily instrumented with tracing. Most of what you'll need to debug a behavior is
already there, you just need to switch on the right level of logging.
Verbose output
The user-visible flag is -v / --verbose:
| Flag | What you get |
|---|---|
| (none) | info-level user-visible messages only |
-v |
debug for uv* crates |
-vv |
trace for uv* crates |
-vvv |
trace for all crates |
These levels are wired up in crates/uv/src/lib.rs (search for Level::DebugUv /
Level::TraceUv) and crates/uv/src/logging.rs. The actual tracing filter strings are built
from RUST_LOG and these flags.
You can also set RUST_LOG directly to override:
$ RUST_LOG=trace cargo run -- lock
$ RUST_LOG=uv_resolver=trace,uv_client=debug cargo run -- pip compile requirements.inProfile and span timing
For performance debugging, build with the tracing-durations-export feature:
$ RUST_LOG=uv=info \
TRACING_DURATIONS_FILE=target/traces/jupyter.ndjson \
cargo run --features tracing-durations-export --profile profiling -- pip compile test/requirements/jupyter.inThen visualize with
tracing-durations-export. Each span in
the codebase (#[instrument]-annotated functions) becomes a row, so you can see where time
goes during resolution, prefetching, downloads, and installs.
Showing resolved settings
--show-settings (hidden flag) prints uv's view of the resolved configuration for the current
command:
$ cargo run -- --show-settings syncThis dumps the merged settings struct (defined per command in crates/uv/src/settings.rs) so
you can see how config files, environment variables, and CLI flags combined.
Common errors
"No solution found"
The resolver formats its error in crates/uv-resolver/src/error.rs
(NoSolutionError::Display). It includes a derivation chain explaining why a particular set
of constraints is unsatisfiable. To see more detail, run with -v to get the resolver's
debug! traces — every fork, every backtrack, every conflict gets logged.
If you're debugging the resolver itself, add tracing::debug! or tracing::trace! calls
inside crates/uv-resolver/src/resolver/mod.rs and rerun with RUST_LOG=uv_resolver=trace.
"No interpreter found"
Discovery errors are produced by crates/uv-python/src/discovery.rs::Error and surface as
PythonNotFound. Setting -v triggers debug! and trace! lines that show every candidate
interpreter the discovery loop considered, where it looked, and why each one was rejected
(version mismatch, broken symlink, wrong implementation, …).
"Failed to fetch metadata"
The HTTP layer logs requests and responses at debug and trace. In particular,
crates/uv-client/src/registry_client.rs logs every request URL, response code, and cache
hit / miss. The linehaul module (crates/uv-client/src/linehaul.rs) is the User-Agent
that PyPI logs. If a registry is rejecting requests, look there first.
TLS errors
TLS errors are produced by crates/uv-client/src/tls.rs and crates/uv-auth/src/middleware.rs.
The error messages distinguish between certificate validation failures, hostname mismatches, and
unsupported cipher suites. --allow-insecure-host (alias --trusted-host) bypasses TLS for a
specific host (with a clear security warning in STYLE.md and the CLI help).
--native-tls and UV_NATIVE_TLS are deprecated as of #18705 (Apr 2026). The default is
rustls + webpki-root-certs.
Cache corruption
Each cache bucket has a version (ARCHIVE_VERSION, the Vn suffix in
crates/uv-cache/src/lib.rs::CacheBucket::to_str). Corrupt entries should be invalidated by
bumping the bucket version. As a quick local fix you can delete the cache:
$ uv cache clean
$ rm -rf ~/.cache/uv # nuclear optionThe cache lives at $UV_CACHE_DIR if set, otherwise ~/.cache/uv on Linux,
~/Library/Caches/uv on macOS, and %LOCALAPPDATA%\uv\cache on Windows.
Inspecting state
The lockfile
uv.lock is a TOML file. The LockVersion constant in
crates/uv-resolver/src/lock/mod.rs controls forward-compatibility. When debugging a lockfile
issue, the easiest path is:
- Reproduce by running the command with
-v. - Diff the resulting
uv.lockagainst the previous one. - Look at
crates/uv-resolver/src/lock/mod.rsfor the read/write code.
The cache directory
uv cache dir prints the cache root. Subdirectories are versioned per-bucket: simple-v18,
wheels-v6, archive-v0, etc. Each bucket has its own layout documented in cache/mod.rs.
The Python install dir
uv python dir prints the managed-Python install root. Each install is laid out as
<implementation>-<version>-<os>-<arch>-<libc>/install/.... A download-metadata.json cache
inside crates/uv-python/ describes every supported build.
The tool dir
uv tool dir prints where per-tool environments live. Each contains the venv plus a
uv-receipt.toml describing what was installed.
Debugger workflows
gdb and lldb work well against a debug build. To break inside the resolver:
$ rust-gdb target/debug/uv -- lock
(gdb) b uv_resolver::resolver::ResolverState::next_iteration
(gdb) runFor more interactive exploration, tokio-console works against a uv process built with the
tokio_unstable cfg flag and the console-subscriber dependency added to crates/uv —
neither is enabled by default.
When all else fails
- File an issue with the full
-vvvoutput anduv --version. - Include the relevant
pyproject.toml,uv.lock, and the smallest reproducing command. - For platform-specific issues (Windows registry, macOS dylibs, Linux musl), include the
platform information uv prints under
uv versionand the relevant Python interpreter info fromuv python list.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.