-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Add an exception handler on Windows #14582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
I tested this by forcing a segfault: diff --git a/crates/uv-client/src/base_client.rs b/crates/uv-client/src/base_client.rs
index 9ddc30e75..45fe0e4e5 100644
--- a/crates/uv-client/src/base_client.rs
+++ b/crates/uv-client/src/base_client.rs
@@ -266,6 +266,7 @@ impl<'a> BaseClientBuilder<'a> {
}
pub fn build(&self) -> BaseClient {
+ unsafe {(1 as *mut i32).write(1);}
// Create user agent.
let mut user_agent_string = format!("uv/{}", version());
Without this patch, it exits quietly: With the patch I get a relatively short error, and Very much open to tweaking the output format. |
4f98bf7 to
7f978f3
Compare
| } | ||
| eprintln!("stack backtrace:\n{backtrace:#}"); | ||
| } | ||
| EXCEPTION_CONTINUE_SEARCH |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason we'd prefer EXCEPTION_CONTINUE_SEARCH (0) over EXCEPTION_EXECUTE_HANDLER (1)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't totally understand the difference in behavior here when we're talking about an unhandled exception filter of which there is only one (as opposed to a vectored exception handler, SEH, etc. where there might actually be a next thing to call). My vague sense is that this alerts a debugger (as a "second chance exception") instead of crashing the process, which seems good?
(Some things I am reading on the internet, e.g., this, and the relevant WINE source, make me think that under the hood the only thing that exists is SEH / unwinding, and something very low level sets up a SEH catch block around main that calls some global function pointer and all that SetUnhandledExceptionFilter does is update that pointer.)
In practice I did this because Google Crashpad returns EXCEPTION_CONTINUE_SEARCH, not EXCEPTION_EXECUTE_HANDLER.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Makes sense if the goal is to delegate to a possible outer SE handler (if any exists) and not treat this filter as the final handler. If we wanted to do filter chaining we'd need to keep the prev filter reference alive and loaded so this is probably good enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, philosophically I want to treat this as something that does an informative print of information while the program is on its way to crashing, not a handler in the sense of something that claims full responsibility for the exception.
I suppose we could store the return value from SetUnhandledExceptionFilter with the pointer to the old filter and call it ourselves, but that feels complicated. There's also apparently the problem that the old filter might have come from a now-unloaded DLL and because there's no explicit unregistration API you have no idea whether that pointer is still valid. Alternatively maybe we should use AddVectoredExceptionHandler which does seem to do a registration/unregistration API with a list of handlers? Or we could do this with an actual SEH try-except handler of our own on the stack (which we don't have to do in Rust if that's hard, I bet we can write a tiny C program to forward to calling uv::main()).
I am trying so hard not to look at the leaked NT source code to figure out what all of this actually does because there's somehow not a lot of documentation, either from MS or from other people. As a data point, on ReactOS (which is reverse-engineered from NT and tries to be compatible with it), returning EXCEPTION_EXECUTE_HANDLER from your custom filter will skip over code in UnhandledExceptionFilter to print a stack trace (custom to ReactOS, not present in NT), show the dialog box (the thing NT apparently no longer does unless you enable it), and start a debugger (present in NT). And indeed UnhandledExceptionFilter is called from a big SEH try/except around calling the start address for the main process or thread, and if you return early from it, the process will just terminate without any of those other niceties.
We've seen a few cases of uv.exe exiting with an exception code as its exit status and no user-visible output (astral-sh#14563 in the field, and astral-sh#13812 in CI). It seems that recent versions of Windows no longer show dialog boxes on access violations (what UNIX calls segfaults) or similar errors. Something is probably sent to Windows Error Reporting, and we can maybe sign up to get the crashes from Microsoft, but the user experience of seeing uv exit with no output is poor, both for end users and during development. While it's possible to opt out of this behavior or set up a debugger, this isn't the default configuration. (See https://superuser.com/q/1246626 for some pointers.) In order to get some output on a crash, we need to install our own default handler for unhandled exceptions (or call all our code inside a Structured Exception Handling __try/__catch block, which is complicated on Rust). This is the moral equivalent of a segfault handler on Windows; the kernel creates a new stack frame and passes arguments to it with some processor state. This commit adds a relatively simple exception handler that leans on Rust's own backtrace implementation and also displays some minimal information from the exception itself. This should be enough info to communicate that something went wrong and let us collect enough information to attempt to debug. There are also a handful of (non-Rust) open-source libraries for this like Breakpad and Crashpad (both from Google) and crashrpt. The approach here, of using SetUnhandledExceptionFilter, seems to be the standard one taken by other such libraries. Crashpad also seems to try to use a newer mechanism for an out-of-tree DLL to report the crash: https://issues.chromium.org/issues/42310037 If we have serious problems with memory corruption, it might be worth adopting some third-party library that has already implemented this approach. (In general, the docs of other crash reporting libraries are worth skimming to understand how these things ought to work.) Co-authored-by: samypr100 <[email protected]>
geofft
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's something a little interesting: on i686, we don't get a proper backtrace. I wonder if the exception handler is called on a different stack or something.
C:\Users\Administrator\uv>cargo build --target i686-pc-windows-msvc -p uv
C:\Users\Administrator\uv>target\i686-pc-windows-msvc\debug\uv run python
error: unhandled exception in uv, please report a bug:
code 0xC0000005 at address 0x2e119b7
EXCEPTION_ACCESS_VIOLATION writing 0x1
eax=00000001 ebx=0effc208 ecx=0ef48ab0 edx=07030fb0 esi=0ef44a80 edi=0effc0a4
eip=02e119b7 ebp=0ef44ec8 esp=0ef44a80 eflags=00010202
stack backtrace:
0: 0x41e265e - std::backtrace::Backtrace::capture
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\backtrace.rs:296
1: 0x1a052e1 - uv::windows_exception::unhandled_exception_filter
at C:\Users\Administrator\uv\crates\uv\src\windows_exception.rs:112
2: 0x75a354b2 - UnhandledExceptionFilter
3: 0x779c7fdf - RtlGetFullPathName_UEx
4: 0x779c7f1b - RtlGetFullPathName_UEx
| } | ||
| eprintln!("stack backtrace:\n{backtrace:#}"); | ||
| } | ||
| EXCEPTION_CONTINUE_SEARCH |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't totally understand the difference in behavior here when we're talking about an unhandled exception filter of which there is only one (as opposed to a vectored exception handler, SEH, etc. where there might actually be a next thing to call). My vague sense is that this alerts a debugger (as a "second chance exception") instead of crashing the process, which seems good?
(Some things I am reading on the internet, e.g., this, and the relevant WINE source, make me think that under the hood the only thing that exists is SEH / unwinding, and something very low level sets up a SEH catch block around main that calls some global function pointer and all that SetUnhandledExceptionFilter does is update that pointer.)
In practice I did this because Google Crashpad returns EXCEPTION_CONTINUE_SEARCH, not EXCEPTION_EXECUTE_HANDLER.
7f978f3 to
7aa37d4
Compare
|
Re that last comment, presumably we can unwind from the provided Also - do we support Windows builds on platforms other than x86, x86-64, and aarch64? Right now the code will fail to compile, but I can add a dummy implementation that doesn't print registers on other platforms. We do seem to handle unknown Windows arches in uv-trampoline-builder, for instance. On the other hand I'm pretty sure that |
At least not to my knowledge |
|
FWIW for a rust crate, there is https://github.com/EmbarkStudios/crash-handling/tree/main/crash-handler |
|
Some context on the state of the art of crash-reporting (you do not need to implement this, just infodumping): You want to spawn two processes: a parent "crash monitor" and a child (your actual app). When the child crashes the parent is signalled to scrape info from the child, generate a minidump, and then sends the minidump to the developer's servers. In this past we had a process analyze itself but "i just segfaulted, time to do a bunch of complex logic and networking" is uhhh dubious. Because shipping two binaries is weird, it's typically to just have a single binary that spawns a second copy of itself. Minidumps, by virtue of containing the memory of stacks, may contain PII so generally you then process the minidump serverside to produce an anonamized summary (error code, stacktrace, system info...). All of this is a ton of work and infra which is why I tell people "yeah just use sentry.io" which in fact uses minidump tooling written in rust. However funnily enough (at least a few years ago) their offerings for rust were basically just a panic hook because a rust app segfaulting was so rare! Hopefully since then they've added segfault handling. But anyway us rolling our own here just so the user gets a vaguely useful diagnostic is Fine. |
| #[cfg(target_arch = "x86_64")] | ||
| fn dump_regs(c: &CONTEXT) { | ||
| eprintln!("rax={:016x} rbx={:016x} rcx={:016x}", c.Rax, c.Rbx, c.Rcx); | ||
| eprintln!("rdx={:016x} rsx={:016x} rdi={:016x}", c.Rdx, c.Rsi, c.Rdi); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rsx is paired with rsi here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops, I'll fix this if I fix something else to save the CI ("rsx" is not a register anyway)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was this meant to be fixed? (noticed it still there in main)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Intentionally not yet to save the CI, but #14619 fixes this.
BurntSushi
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be good to try and fix printing so that we don't go through eprintln!, but this otherwise LGTM. (Noting that I don't really have a lot of Windows experience, so my review isn't worth much.)
| ) -> i32 { | ||
| // TODO: Really we should not be using eprintln here because Stderr is not async-signal-safe. | ||
| // Probably we should be calling the console APIs directly. | ||
| eprintln!("error: unhandled exception in uv, please report a bug:"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, eprintln! will try to acquire a lock. If that lock is held by some other part of the code (which doesn't seem that unlikely to me) when this handler is executed, then presumably this will deadlock. (IDK if acquiring locks is async-signal-safe on Windows either.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the lock is the thing I was thinking of re async-signal-safety (which isn't exactly a phrase used on Windows, but the concept is exactly the same because you get called in a new stack frame at some arbitrary point when an exception happens) and I do expect that to be a risk. I don't see a lockless/async-signal-safe way to print stuff in std, the console APIs looked more complicated than I wanted to deal with (you gotta get a handle, do encoding, etc.), and I sort of assume that Windows' implementation of POSIX write isn't actually async-signal-safe.
FWIW I went with eprintln! because we're using anstream::eprintln! elsewhere for printing messages, which I assume wraps it and takes out the same lock. (It just doesn't trigger the Clippy lint.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can use AsRawHandle on the result of std::io::stderr, and then FromRawHandle to create a File. Then you should be able to write to that. That won't acquire any locks.
I do not know if the underlying syscall (WriteConsoleW) is async-signal-safe on Windows, but this will at least avoid the possible deadlock that can occur by using eprintln!.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, hm, that looks easier than what https://github.com/rust-lang/rust/blob/master/library/std/src/sys/stdio/windows.rs and https://github.com/rust-lang/rust/blob/master/library/std/src/sys/pal/windows/handle.rs are doing (which I think is the code behind the stderr lock). There are two implementations there:
- If stderr is a console that either uses a non-UTF-8 code page or is on Windows 7, then it writes UTF-16 with
WriteConsoleW. There's some handling for incomplete/invalid UTF-8 which wouldn't apply since we only need to writestrs. But I'm surprised at the code calling Windows API functionMultiByteToWideCharinstead of e.g.str::encode_utf16(), is that necessary? - If stderr is either not a console, or the console uses the UTF-8 code page (and we're not on Windows 7), then we write bytes with
FromRawHandle+write, which callsNtWriteFile(I got a little scared by the thing it does toWaitForSingleObjectbut I missed that this function is public API and we wouldn't have to reimplement it).
It seems like we have to have both implementations, in that WriteConsole won't work if stderr is redirected to a file and writing UTF-8 won't work if stderr is a non-UTF-8-code-page console. But it doesn't seem as bad as I was afraid of.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yeah, I think I'm wrong. Because writing to File won't call WriteConsole. So yeah, I think if it's a console, we'd have to do our own Windows FFI stuff. But otherwise we should be able to just get a File and write to it like normal.
As for MultiByteToWideChar, it looks like we used to use str::encode_utf16, but it was switched due to performance. I don't think we'll care about perf here, so using str::encode_utf16 seems fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Took a stab at this in #14619. Style feedback is more than welcome.
geofft
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the context @Gankra! Also recording here the link you sent me to https://github.com/rust-minidump/minidump-pipeline so I don't lose it, both of these answer my question of "how are you supposed to do this in Rust."
It does seem to me like if we want to do something more complicated we should go with one of the third-party SaaS options, either some vendor that specializes in this sort of reporting or signing up for Microsoft's own Windows Error Reporting thing. Adding an out-of-process handler for uv.exe seems complicated and not something we should do by default given that we've seen a single-digit number of segfaults and we care about startup performance.
| ) -> i32 { | ||
| // TODO: Really we should not be using eprintln here because Stderr is not async-signal-safe. | ||
| // Probably we should be calling the console APIs directly. | ||
| eprintln!("error: unhandled exception in uv, please report a bug:"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the lock is the thing I was thinking of re async-signal-safety (which isn't exactly a phrase used on Windows, but the concept is exactly the same because you get called in a new stack frame at some arbitrary point when an exception happens) and I do expect that to be a risk. I don't see a lockless/async-signal-safe way to print stuff in std, the console APIs looked more complicated than I wanted to deal with (you gotta get a handle, do encoding, etc.), and I sort of assume that Windows' implementation of POSIX write isn't actually async-signal-safe.
FWIW I went with eprintln! because we're using anstream::eprintln! elsewhere for printing messages, which I assume wraps it and takes out the same lock. (It just doesn't trigger the Clippy lint.)
| #[cfg(target_arch = "x86_64")] | ||
| fn dump_regs(c: &CONTEXT) { | ||
| eprintln!("rax={:016x} rbx={:016x} rcx={:016x}", c.Rax, c.Rbx, c.Rcx); | ||
| eprintln!("rdx={:016x} rsx={:016x} rdi={:016x}", c.Rdx, c.Rsi, c.Rdi); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops, I'll fix this if I fix something else to save the CI ("rsx" is not a register anyway)
This MR contains the following updates: | Package | Update | Change | |---|---|---| | [astral-sh/uv](https://github.com/astral-sh/uv) | minor | `0.7.19` -> `0.8.3` | MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot). **Proposed changes to behavior should be submitted there as MRs.** --- ### Release Notes <details> <summary>astral-sh/uv (astral-sh/uv)</summary> ### [`v0.8.3`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#083) [Compare Source](astral-sh/uv@0.8.2...0.8.3) ##### Python - Add CPython 3.14.0rc1 See the [`python-build-standalone` release notes](https://github.com/astral-sh/python-build-standalone/releases/tag/20250723) for more details. ##### Enhancements - Allow non-standard entrypoint names in `uv_build` ([#​14867](astral-sh/uv#14867)) - Publish riscv64 wheels to PyPI ([#​14852](astral-sh/uv#14852)) ##### Bug fixes - Avoid writing redacted credentials to tool receipt ([#​14855](astral-sh/uv#14855)) - Respect `--with` versions over base environment versions ([#​14863](astral-sh/uv#14863)) - Respect credentials from all defined indexes ([#​14858](astral-sh/uv#14858)) - Fix missed stabilization of removal of registry entry during Python uninstall ([#​14859](astral-sh/uv#14859)) - Improve concurrency safety of Python downloads into cache ([#​14846](astral-sh/uv#14846)) ##### Documentation - Fix typos in `uv_build` reference documentation ([#​14853](astral-sh/uv#14853)) - Move the "Cargo" install method further down in docs ([#​14842](astral-sh/uv#14842)) ### [`v0.8.2`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#082) [Compare Source](astral-sh/uv@0.8.1...0.8.2) ##### Enhancements - Add derivation chains for dependency errors ([#​14824](astral-sh/uv#14824)) ##### Configuration - Add `UV_INIT_BUILD_BACKEND` ([#​14821](astral-sh/uv#14821)) ##### Bug fixes - Avoid reading files in the environment bin that are not entrypoints ([#​14830](astral-sh/uv#14830)) - Avoid removing empty directories when constructing virtual environments ([#​14822](astral-sh/uv#14822)) - Preserve index URL priority order when writing to pyproject.toml ([#​14831](astral-sh/uv#14831)) ##### Rust API - Expose `tls_built_in_root_certs` for client ([#​14816](astral-sh/uv#14816)) ##### Documentation - Archive the 0.7.x changelog ([#​14819](astral-sh/uv#14819)) ### [`v0.8.1`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#081) [Compare Source](astral-sh/uv@0.8.0...0.8.1) ##### Enhancements - Add support for `HF_TOKEN` ([#​14797](astral-sh/uv#14797)) - Allow `--config-settings-package` to apply configuration settings at the package level ([#​14573](astral-sh/uv#14573)) - Create (e.g.) `python3.13t` executables in `uv venv` ([#​14764](astral-sh/uv#14764)) - Disallow writing symlinks outside the source distribution target directory ([#​12259](astral-sh/uv#12259)) - Elide traceback when `python -m uv` in interrupted with Ctrl-C on Windows ([#​14715](astral-sh/uv#14715)) - Match `--bounds` formatting for `uv_build` bounds in `uv init` ([#​14731](astral-sh/uv#14731)) - Support `extras` and `dependency_groups` markers in PEP 508 grammar ([#​14753](astral-sh/uv#14753)) - Support `extras` and `dependency_groups` markers on `uv pip install` and `uv pip sync` ([#​14755](astral-sh/uv#14755)) - Add hint to use `uv self version` when `uv version` cannot find a project ([#​14738](astral-sh/uv#14738)) - Improve error reporting when removing Python versions from the Windows registry ([#​14722](astral-sh/uv#14722)) - Make warnings about masked `[tool.uv]` fields more precise ([#​14325](astral-sh/uv#14325)) ##### Preview features - Emit JSON output in `uv sync` with `--quiet` ([#​14810](astral-sh/uv#14810)) ##### Bug fixes - Allow removal of virtual environments with missing interpreters ([#​14812](astral-sh/uv#14812)) - Apply `Cache-Control` overrides to response, not request headers ([#​14736](astral-sh/uv#14736)) - Copy entry points into ephemeral environments to ensure layers are respected ([#​14790](astral-sh/uv#14790)) - Workaround Jupyter Lab application directory discovery in ephemeral environments ([#​14790](astral-sh/uv#14790)) - Enforce `requires-python` in `pylock.toml` ([#​14787](astral-sh/uv#14787)) - Fix kebab casing of `README` variants in build backend ([#​14762](astral-sh/uv#14762)) - Improve concurrency resilience of removing Python versions from the Windows registry ([#​14717](astral-sh/uv#14717)) - Retry HTTP requests on invalid data errors ([#​14703](astral-sh/uv#14703)) - Update virtual environment removal to delete `pyvenv.cfg` last ([#​14808](astral-sh/uv#14808)) - Error on unknown fields in `dependency-metadata` ([#​14801](astral-sh/uv#14801)) ##### Documentation - Recommend installing `setup-uv` after `setup-python` in Github Actions integration guide ([#​14741](astral-sh/uv#14741)) - Clarify which portions of `requires-python` behavior are consistent with pip ([#​14752](astral-sh/uv#14752)) ### [`v0.8.0`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#080) [Compare Source](astral-sh/uv@0.7.22...0.8.0) Since we released uv [0.7.0](https://github.com/astral-sh/uv/releases/tag/0.7.0) in April, we've accumulated various changes that improve correctness and user experience, but could break some workflows. This release contains those changes; many have been marked as breaking out of an abundance of caution. We expect most users to be able to upgrade without making changes. This release also includes the stabilization of a couple `uv python install` features, which have been available under preview since late last year. ##### Breaking changes - **Install Python executables into a directory on the `PATH` ([#​14626](astral-sh/uv#14626 `uv python install` now installs a versioned Python executable (e.g., `python3.13`) into a directory on the `PATH` (e.g., `~/.local/bin`) by default. This behavior has been available under the `--preview` flag since [Oct 2024](astral-sh/uv#8458). This change should not be breaking unless it shadows a Python executable elsewhere on the `PATH`. To install unversioned executables, i.e., `python3` and `python`, use the `--default` flag. The `--default` flag has also been in preview, but is not stabilized in this release. Note that these executables point to the base Python installation and only include the standard library. That means they will not include dependencies from your current project (use `uv run python` instead) and you cannot install packages into their environment (use `uvx --with <package> python` instead). As with tool installation, the target directory respects common variables like `XDG_BIN_HOME` and can be overridden with a `UV_PYTHON_BIN_DIR` variable. You can opt out of this behavior with `uv python install --no-bin` or `UV_PYTHON_INSTALL_BIN=0`. See the [documentation on installing Python executables](https://docs.astral.sh/uv/concepts/python-versions/#installing-python-executables) for more details. - **Register Python versions with the Windows Registry ([#​14625](astral-sh/uv#14625 `uv python install` now registers the installed Python version with the Windows Registry as specified by [PEP 514](https://peps.python.org/pep-0514/). This allows using uv installed Python versions via the `py` launcher. This behavior has been available under the `--preview` flag since [Jan 2025](astral-sh/uv#10634). This change should not be breaking, as using the uv Python versions with `py` requires explicit opt in. You can opt out of this behavior with `uv python install --no-registry` or `UV_PYTHON_INSTALL_REGISTRY=0`. - **Prompt before removing an existing directory in `uv venv` ([#​14309](astral-sh/uv#14309 Previously, `uv venv` would remove an existing virtual environment without confirmation. While this is consistent with the behavior of project commands (e.g., `uv sync`), it's surprising to users that are using imperative workflows (i.e., `uv pip`). Now, `uv venv` will prompt for confirmation before removing an existing virtual environment. **If not in an interactive context, uv will still remove the virtual environment for backwards compatibility. However, this behavior is likely to change in a future release.** The behavior for other commands (e.g., `uv sync`) is unchanged. You can opt out of this behavior by setting `UV_VENV_CLEAR=1` or passing the `--clear` flag. - **Validate that discovered interpreters meet the Python preference ([#​7934](astral-sh/uv#7934 uv allows opting out of its managed Python versions with the `--no-managed-python` and `python-preference` options. Previously, uv would not enforce this option for Python interpreters discovered on the `PATH`. For example, if a symlink to a managed Python interpreter was created, uv would allow it to be used even if `--no-managed-python` was provided. Now, uv ignores Python interpreters that do not match the Python preference *unless* they are in an active virtual environment or are explicitly requested, e.g., with `--python /path/to/python3.13`. Similarly, uv would previously not invalidate existing project environments if they did not match the Python preference. Now, uv will invalidate and recreate project environments when the Python preference changes. You can opt out of this behavior by providing the explicit path to the Python interpreter providing `--managed-python` / `--no-managed-python` matching the interpreter you want. - **Install dependencies without build systems when they are `path` sources ([#​14413](astral-sh/uv#14413 When working on a project, uv uses the [presence of a build system](https://docs.astral.sh/uv/concepts/projects/config/#build-systems) to determine if it should be built and installed into the environment. However, when a project is a dependency of another project, it can be surprising for the dependency to be missing from the environment. Previously, uv would not build and install dependencies with [`path` sources](https://docs.astral.sh/uv/concepts/projects/dependencies/#path) unless they declared a build system or set `tool.uv.package = true`. Now, dependencies with `path` sources are built and installed regardless of the presence of a build system. If a build system is not present, the `setuptools.build_meta:__legacy__ ` backend will be used (per [PEP 517](https://peps.python.org/pep-0517/#source-trees)). You can opt out of this behavior by setting `package = false` in the source declaration, e.g.: ```toml [tool.uv.sources] foo = { path = "./foo", package = false } ``` Or, by setting `tool.uv.package = false` in the dependent `pyproject.toml`. See the documentation on [virtual dependencies](https://docs.astral.sh/uv/concepts/projects/dependencies/#virtual-dependencies) for details. - **Install dependencies without build systems when they are workspace members ([#​14663](astral-sh/uv#14663 As described above for dependencies with `path` sources, uv previously would not build and install workspace members that did not declare a build system. Now, uv will build and install workspace members that are a dependency of *another* workspace member regardless of the presence of a build system. The behavior is unchanged for workspace members that are not included in the `project.dependencies`, `project.optional-dependencies`, or `dependency-groups` tables of another workspace member. You can opt out of this behavior by setting `tool.uv.package = false` in the workspace member's `pyproject.toml`. See the documentation on [virtual dependencies](https://docs.astral.sh/uv/concepts/projects/dependencies/#virtual-dependencies) for details. - **Bump `--python-platform linux` to `manylinux_2_28` ([#​14300](astral-sh/uv#14300 uv allows performing [platform-specific resolution](https://docs.astral.sh/uv/concepts/resolution/#platform-specific-resolution) for explicit targets and provides short aliases, e.g., `linux`, for common targets. Previously, the default target for `--python-platform linux` was `manylinux_2_17`, which is compatible with most Linux distributions from 2014 or newer. We now default to `manylinux_2_28`, which is compatible with most Linux distributions from 2019 or newer. This change follows the lead of other tools, such as `cibuildwheel`, which changed their default to `manylinux_2_28` in [Mar 2025](pypa/cibuildwheel#2330). This change only affects users requesting a specific target platform. Otherwise, uv detects the `manylinux` target from your local glibc version. You can opt out of this behavior by using `--python-platform x86_64-manylinux_2_17` instead. - **Remove `uv version` fallback ([#​14161](astral-sh/uv#14161 In [Apr 2025](astral-sh/uv#12349), uv changed the `uv version` command to an interface for viewing and updating the version of the current project. However, when outside a project, `uv version` would continue to display uv's version for backwards compatibility. Now, when used outside of a project, `uv version` will fail. You cannot opt out of this behavior. Use `uv self version` instead. - **Require `--global` for removal of the global Python pin ([#​14169](astral-sh/uv#14169 Previously, `uv python pin --rm` would allow you to remove the global Python pin without opt in. Now, uv requires the `--global` flag to remove the global Python pin. You cannot opt out of this behavior. Use the `--global` flag instead. - **Support conflicting editable settings across groups ([#​14197](astral-sh/uv#14197 Previously, uv would always treat a package as editable if any requirement requested it as editable. However, this prevented users from declaring `path` sources that toggled the `editable` setting across dependency groups. Now, uv allows declaring different `editable` values for conflicting groups. However, if a project includes a path dependency twice, once with `editable = true` and once without any editable annotation, those are now considered conflicting, and uv will exit with an error. You cannot opt out of this behavior. Use consistent `editable` settings or [mark groups as conflicting](https://docs.astral.sh/uv/concepts/projects/config/#conflicting-dependencies). - **Make `uv_build` the default build backend in `uv init` ([#​14661](astral-sh/uv#14661 The uv build backend (`uv_build`) was [stabilized in uv 0.7.19](https://github.com/astral-sh/uv/releases/tag/0.7.19). Now, it is the default build backend for `uv init --package` and `uv init --lib`. Previously, `hatchling` was the default build backend. A build backend is still not used without opt-in in `uv init`, but we expect to change this in a future release. You can opt out of this behavior with `uv init --build-backend hatchling`. - **Set default `UV_TOOL_BIN_DIR` on Docker images ([#​13391](astral-sh/uv#13391 Previously, `UV_TOOL_BIN_DIR` was not set in Docker images which meant that `uv tool install` did not install tools into a directory on the `PATH` without additional configuration. Now, `UV_TOOL_BIN_DIR` is set to `/usr/local/bin` in all Docker derived images. When the default image user is overridden (e.g. `USER <UID>`) with a less privileged user, this may cause `uv tool install` to fail. You can opt out of this behavior by setting an alternative `UV_TOOL_BIN_DIR`. - **Update `--check` to return an exit code of 1 ([#​14167](astral-sh/uv#14167 uv uses an exit code of 1 to indicate a "successful failure" and an exit code of 2 to indicate an "error". Previously, `uv lock --check` and `uv sync --check` would exit with a code of 2 when the lockfile or environment were outdated. Now, uv will exit with a code of 1. You cannot opt out of this behavior. - **Use an ephemeral environment for `uv run --with` invocations ([#​14447](astral-sh/uv#14447 When using `uv run --with`, uv layers the requirements requested using `--with` into another virtual environment and caches it. Previously, uv would invoke the Python interpreter in this layered environment. However, this allows poisoning the cached environment and introduces race conditions for concurrent invocations. Now, uv will layer *another* empty virtual environment on top of the cached environment and invoke the Python interpreter there. This should only cause breakage in cases where the environment is being inspected at runtime. You cannot opt out of this behavior. - **Restructure the `uv venv` command output and exit codes ([#​14546](astral-sh/uv#14546 Previously, uv used `miette` to format the `uv venv` output. However, this was inconsistent with most of the uv CLI. Now, the output is a little different and the exit code has switched from 1 to 2 for some error cases. You cannot opt out of this behavior. - **Default to `--workspace` when adding subdirectories ([#​14529](astral-sh/uv#14529 When using `uv add` to add a subdirectory in a workspace, uv now defaults to adding the target as a workspace member. You can opt out of this behavior by providing `--no-workspace`. - **Add missing validations for disallowed `uv.toml` fields ([#​14322](astral-sh/uv#14322 uv does not allow some settings in the `uv.toml`. Previously, some settings were silently ignored when present in the `uv.toml`. Now, uv will error. You cannot opt out of this behavior. Use `--no-config` or remove the invalid settings. ##### Configuration - Add support for toggling Python bin and registry install options via env vars ([#​14662](astral-sh/uv#14662)) ### [`v0.7.22`](https://github.com/astral-sh/uv/releases/tag/0.7.22) [Compare Source](astral-sh/uv@0.7.21...0.7.22) #### Release Notes ##### Python - Upgrade GraalPy to 24.2.2 See the [GraalPy release notes](https://github.com/oracle/graalpython/releases/tag/graal-24.2.2) for more details. ##### Configuration - Add `UV_COMPILE_BYTECODE_TIMEOUT` environment variable ([#​14369](astral-sh/uv#14369)) - Allow users to override index `cache-control` headers ([#​14620](astral-sh/uv#14620)) - Add `UV_LIBC` to override libc selection in multi-libc environment ([#​14646](astral-sh/uv#14646)) ##### Bug fixes - Fix `--all-arches` when paired with `--only-downloads` ([#​14629](astral-sh/uv#14629)) - Skip Windows Python interpreters that return a broken MSIX package code ([#​14636](astral-sh/uv#14636)) - Warn on invalid `uv.toml` when provided via direct path ([#​14653](astral-sh/uv#14653)) - Improve async signal safety in Windows exception handler ([#​14619](astral-sh/uv#14619)) ##### Documentation - Mention the `revision` in the lockfile versioning doc ([#​14634](astral-sh/uv#14634)) - Move "Conflicting dependencies" to the "Resolution" page ([#​14633](astral-sh/uv#14633)) - Rename "Dependency specifiers" section to exclude PEP 508 reference ([#​14631](astral-sh/uv#14631)) - Suggest `uv cache clean` prior to `--reinstall` ([#​14659](astral-sh/uv#14659)) ##### Preview features - Make preview Python registration on Windows non-fatal ([#​14614](astral-sh/uv#14614)) - Update preview installation of Python executables to be non-fatal ([#​14612](astral-sh/uv#14612)) - Add `uv python update-shell` ([#​14627](astral-sh/uv#14627)) #### Install uv 0.7.22 ##### Install prebuilt binaries via shell script ```sh curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.7.22/uv-installer.sh | sh ``` ##### Install prebuilt binaries via powershell script ```sh powershell -ExecutionPolicy Bypass -c "irm https://github.com/astral-sh/uv/releases/download/0.7.22/uv-installer.ps1 | iex" ``` #### Download uv 0.7.22 | File | Platform | Checksum | |--------|----------|----------| | [uv-aarch64-apple-darwin.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-aarch64-apple-darwin.tar.gz) | Apple Silicon macOS | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-aarch64-apple-darwin.tar.gz.sha256) | | [uv-x86\_64-apple-darwin.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-x86_64-apple-darwin.tar.gz) | Intel macOS | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-x86_64-apple-darwin.tar.gz.sha256) | | [uv-aarch64-pc-windows-msvc.zip](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-aarch64-pc-windows-msvc.zip) | ARM64 Windows | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-aarch64-pc-windows-msvc.zip.sha256) | | [uv-i686-pc-windows-msvc.zip](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-i686-pc-windows-msvc.zip) | x86 Windows | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-i686-pc-windows-msvc.zip.sha256) | | [uv-x86\_64-pc-windows-msvc.zip](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-x86_64-pc-windows-msvc.zip) | x64 Windows | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-x86_64-pc-windows-msvc.zip.sha256) | | [uv-aarch64-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-aarch64-unknown-linux-gnu.tar.gz) | ARM64 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-aarch64-unknown-linux-gnu.tar.gz.sha256) | | [uv-i686-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-i686-unknown-linux-gnu.tar.gz) | x86 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-i686-unknown-linux-gnu.tar.gz.sha256) | | [uv-powerpc64-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-powerpc64-unknown-linux-gnu.tar.gz) | PPC64 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-powerpc64-unknown-linux-gnu.tar.gz.sha256) | | [uv-powerpc64le-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-powerpc64le-unknown-linux-gnu.tar.gz) | PPC64LE Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-powerpc64le-unknown-linux-gnu.tar.gz.sha256) | | [uv-riscv64gc-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-riscv64gc-unknown-linux-gnu.tar.gz) | RISCV Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-riscv64gc-unknown-linux-gnu.tar.gz.sha256) | | [uv-s390x-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-s390x-unknown-linux-gnu.tar.gz) | S390x Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-s390x-unknown-linux-gnu.tar.gz.sha256) | | [uv-x86\_64-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-x86_64-unknown-linux-gnu.tar.gz) | x64 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-x86_64-unknown-linux-gnu.tar.gz.sha256) | | [uv-armv7-unknown-linux-gnueabihf.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-armv7-unknown-linux-gnueabihf.tar.gz) | ARMv7 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-armv7-unknown-linux-gnueabihf.tar.gz.sha256) | | [uv-aarch64-unknown-linux-musl.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-aarch64-unknown-linux-musl.tar.gz) | ARM64 MUSL Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-aarch64-unknown-linux-musl.tar.gz.sha256) | | [uv-i686-unknown-linux-musl.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-i686-unknown-linux-musl.tar.gz) | x86 MUSL Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-i686-unknown-linux-musl.tar.gz.sha256) | | [uv-x86\_64-unknown-linux-musl.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-x86_64-unknown-linux-musl.tar.gz) | x64 MUSL Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-x86_64-unknown-linux-musl.tar.gz.sha256) | | [uv-arm-unknown-linux-musleabihf.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-arm-unknown-linux-musleabihf.tar.gz) | ARMv6 MUSL Linux (Hardfloat) | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-arm-unknown-linux-musleabihf.tar.gz.sha256) | | [uv-armv7-unknown-linux-musleabihf.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-armv7-unknown-linux-musleabihf.tar.gz) | ARMv7 MUSL Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.22/uv-armv7-unknown-linux-musleabihf.tar.gz.sha256) | ### [`v0.7.21`](https://github.com/astral-sh/uv/releases/tag/0.7.21) [Compare Source](astral-sh/uv@0.7.20...0.7.21) #### Release Notes ##### Python - Restore the SQLite `fts4`, `fts5`, `rtree`, and `geopoly` extensions on macOS and Linux See the [`python-build-standalone` release notes](https://github.com/astral-sh/python-build-standalone/releases/tag/20250712) for more details. ##### Enhancements - Add `--python-platform` to `uv sync` ([#​14320](astral-sh/uv#14320)) - Support pre-releases in `uv version --bump` ([#​13578](astral-sh/uv#13578)) - Add `-w` shorthand for `--with` ([#​14530](astral-sh/uv#14530)) - Add an exception handler on Windows to display information on crash ([#​14582](astral-sh/uv#14582)) - Add hint when Python downloads are disabled ([#​14522](astral-sh/uv#14522)) - Add `UV_HTTP_RETRIES` to customize retry counts ([#​14544](astral-sh/uv#14544)) - Follow leaf symlinks matched by globs in `cache-key` ([#​13438](astral-sh/uv#13438)) - Support parent path components (`..`) in globs in `cache-key` ([#​13469](astral-sh/uv#13469)) - Improve `cache-key` performance ([#​13469](astral-sh/uv#13469)) ##### Preview features - Add `uv sync --output-format json` ([#​13689](astral-sh/uv#13689)) ##### Bug fixes - Do not re-resolve with a new Python version in `uv tool` if it is incompatible with `--python` ([#​14606](astral-sh/uv#14606)) ##### Documentation - Document how to nest dependency groups with `include-group` ([#​14539](astral-sh/uv#14539)) - Fix repeated word in Pyodide doc ([#​14554](astral-sh/uv#14554)) - Update CONTRIBUTING.md with instructions to format Markdown files via Docker ([#​14246](astral-sh/uv#14246)) - Fix version number for `setup-python` ([#​14533](astral-sh/uv#14533)) #### Install uv 0.7.21 ##### Install prebuilt binaries via shell script ```sh curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.7.21/uv-installer.sh | sh ``` ##### Install prebuilt binaries via powershell script ```sh powershell -ExecutionPolicy Bypass -c "irm https://github.com/astral-sh/uv/releases/download/0.7.21/uv-installer.ps1 | iex" ``` #### Download uv 0.7.21 | File | Platform | Checksum | |--------|----------|----------| | [uv-aarch64-apple-darwin.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-aarch64-apple-darwin.tar.gz) | Apple Silicon macOS | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-aarch64-apple-darwin.tar.gz.sha256) | | [uv-x86\_64-apple-darwin.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-x86_64-apple-darwin.tar.gz) | Intel macOS | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-x86_64-apple-darwin.tar.gz.sha256) | | [uv-aarch64-pc-windows-msvc.zip](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-aarch64-pc-windows-msvc.zip) | ARM64 Windows | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-aarch64-pc-windows-msvc.zip.sha256) | | [uv-i686-pc-windows-msvc.zip](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-i686-pc-windows-msvc.zip) | x86 Windows | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-i686-pc-windows-msvc.zip.sha256) | | [uv-x86\_64-pc-windows-msvc.zip](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-x86_64-pc-windows-msvc.zip) | x64 Windows | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-x86_64-pc-windows-msvc.zip.sha256) | | [uv-aarch64-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-aarch64-unknown-linux-gnu.tar.gz) | ARM64 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-aarch64-unknown-linux-gnu.tar.gz.sha256) | | [uv-i686-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-i686-unknown-linux-gnu.tar.gz) | x86 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-i686-unknown-linux-gnu.tar.gz.sha256) | | [uv-powerpc64-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-powerpc64-unknown-linux-gnu.tar.gz) | PPC64 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-powerpc64-unknown-linux-gnu.tar.gz.sha256) | | [uv-powerpc64le-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-powerpc64le-unknown-linux-gnu.tar.gz) | PPC64LE Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-powerpc64le-unknown-linux-gnu.tar.gz.sha256) | | [uv-riscv64gc-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-riscv64gc-unknown-linux-gnu.tar.gz) | RISCV Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-riscv64gc-unknown-linux-gnu.tar.gz.sha256) | | [uv-s390x-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-s390x-unknown-linux-gnu.tar.gz) | S390x Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-s390x-unknown-linux-gnu.tar.gz.sha256) | | [uv-x86\_64-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-x86_64-unknown-linux-gnu.tar.gz) | x64 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-x86_64-unknown-linux-gnu.tar.gz.sha256) | | [uv-armv7-unknown-linux-gnueabihf.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-armv7-unknown-linux-gnueabihf.tar.gz) | ARMv7 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-armv7-unknown-linux-gnueabihf.tar.gz.sha256) | | [uv-aarch64-unknown-linux-musl.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-aarch64-unknown-linux-musl.tar.gz) | ARM64 MUSL Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-aarch64-unknown-linux-musl.tar.gz.sha256) | | [uv-i686-unknown-linux-musl.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-i686-unknown-linux-musl.tar.gz) | x86 MUSL Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-i686-unknown-linux-musl.tar.gz.sha256) | | [uv-x86\_64-unknown-linux-musl.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-x86_64-unknown-linux-musl.tar.gz) | x64 MUSL Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-x86_64-unknown-linux-musl.tar.gz.sha256) | | [uv-arm-unknown-linux-musleabihf.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-arm-unknown-linux-musleabihf.tar.gz) | ARMv6 MUSL Linux (Hardfloat) | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-arm-unknown-linux-musleabihf.tar.gz.sha256) | | [uv-armv7-unknown-linux-musleabihf.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-armv7-unknown-linux-musleabihf.tar.gz) | ARMv7 MUSL Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.21/uv-armv7-unknown-linux-musleabihf.tar.gz.sha256) | ### [`v0.7.20`](https://github.com/astral-sh/uv/releases/tag/0.7.20) [Compare Source](astral-sh/uv@0.7.19...0.7.20) #### Release Notes ##### Python - Add Python 3.14.0b4 - Add zstd support to Python 3.14 on Unix (it already was available on Windows) - Add PyPy 7.3.20 (for Python 3.11.13) See the [PyPy](https://pypy.org/posts/2025/07/pypy-v7320-release.html) and [`python-build-standalone`](https://github.com/astral-sh/python-build-standalone/releases/tag/20250708) release notes for more details. ##### Enhancements - Add `--workspace` flag to `uv add` ([#​14496](astral-sh/uv#14496)) - Add auto-detection for Intel GPUs ([#​14386](astral-sh/uv#14386)) - Drop trailing arguments when writing shebangs ([#​14519](astral-sh/uv#14519)) - Add debug message when skipping Python downloads ([#​14509](astral-sh/uv#14509)) - Add support for declaring multiple modules in namespace packages ([#​14460](astral-sh/uv#14460)) ##### Bug fixes - Revert normalization of trailing slashes on index URLs ([#​14511](astral-sh/uv#14511)) - Fix forced resolution with all extras in `uv version` ([#​14434](astral-sh/uv#14434)) - Fix handling of pre-releases in preferences ([#​14498](astral-sh/uv#14498)) - Remove transparent variants in `uv-extract` to enable retries ([#​14450](astral-sh/uv#14450)) ##### Rust API - Add method to get packages involved in a `NoSolutionError` ([#​14457](astral-sh/uv#14457)) - Make `ErrorTree` for `NoSolutionError` public ([#​14444](astral-sh/uv#14444)) ##### Documentation - Finish incomplete sentence in pip migration guide ([#​14432](astral-sh/uv#14432)) - Remove `cache-dependency-glob` examples for `setup-uv` ([#​14493](astral-sh/uv#14493)) - Remove `uv pip sync` suggestion with `pyproject.toml` ([#​14510](astral-sh/uv#14510)) - Update documentation for GitHub to use `setup-uv@v6` ([#​14490](astral-sh/uv#14490)) #### Install uv 0.7.20 ##### Install prebuilt binaries via shell script ```sh curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.7.20/uv-installer.sh | sh ``` ##### Install prebuilt binaries via powershell script ```sh powershell -ExecutionPolicy Bypass -c "irm https://github.com/astral-sh/uv/releases/download/0.7.20/uv-installer.ps1 | iex" ``` #### Download uv 0.7.20 | File | Platform | Checksum | |--------|----------|----------| | [uv-aarch64-apple-darwin.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-aarch64-apple-darwin.tar.gz) | Apple Silicon macOS | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-aarch64-apple-darwin.tar.gz.sha256) | | [uv-x86\_64-apple-darwin.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-x86_64-apple-darwin.tar.gz) | Intel macOS | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-x86_64-apple-darwin.tar.gz.sha256) | | [uv-aarch64-pc-windows-msvc.zip](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-aarch64-pc-windows-msvc.zip) | ARM64 Windows | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-aarch64-pc-windows-msvc.zip.sha256) | | [uv-i686-pc-windows-msvc.zip](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-i686-pc-windows-msvc.zip) | x86 Windows | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-i686-pc-windows-msvc.zip.sha256) | | [uv-x86\_64-pc-windows-msvc.zip](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-x86_64-pc-windows-msvc.zip) | x64 Windows | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-x86_64-pc-windows-msvc.zip.sha256) | | [uv-aarch64-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-aarch64-unknown-linux-gnu.tar.gz) | ARM64 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-aarch64-unknown-linux-gnu.tar.gz.sha256) | | [uv-i686-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-i686-unknown-linux-gnu.tar.gz) | x86 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-i686-unknown-linux-gnu.tar.gz.sha256) | | [uv-powerpc64-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-powerpc64-unknown-linux-gnu.tar.gz) | PPC64 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-powerpc64-unknown-linux-gnu.tar.gz.sha256) | | [uv-powerpc64le-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-powerpc64le-unknown-linux-gnu.tar.gz) | PPC64LE Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-powerpc64le-unknown-linux-gnu.tar.gz.sha256) | | [uv-riscv64gc-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-riscv64gc-unknown-linux-gnu.tar.gz) | RISCV Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-riscv64gc-unknown-linux-gnu.tar.gz.sha256) | | [uv-s390x-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-s390x-unknown-linux-gnu.tar.gz) | S390x Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-s390x-unknown-linux-gnu.tar.gz.sha256) | | [uv-x86\_64-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-x86_64-unknown-linux-gnu.tar.gz) | x64 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-x86_64-unknown-linux-gnu.tar.gz.sha256) | | [uv-armv7-unknown-linux-gnueabihf.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-armv7-unknown-linux-gnueabihf.tar.gz) | ARMv7 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-armv7-unknown-linux-gnueabihf.tar.gz.sha256) | | [uv-aarch64-unknown-linux-musl.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-aarch64-unknown-linux-musl.tar.gz) | ARM64 MUSL Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-aarch64-unknown-linux-musl.tar.gz.sha256) | | [uv-i686-unknown-linux-musl.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-i686-unknown-linux-musl.tar.gz) | x86 MUSL Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-i686-unknown-linux-musl.tar.gz.sha256) | | [uv-x86\_64-unknown-linux-musl.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-x86_64-unknown-linux-musl.tar.gz) | x64 MUSL Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-x86_64-unknown-linux-musl.tar.gz.sha256) | | [uv-arm-unknown-linux-musleabihf.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-arm-unknown-linux-musleabihf.tar.gz) | ARMv6 MUSL Linux (Hardfloat) | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-arm-unknown-linux-musleabihf.tar.gz.sha256) | | [uv-armv7-unknown-linux-musleabihf.tar.gz](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-armv7-unknown-linux-musleabihf.tar.gz) | ARMv7 MUSL Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.7.20/uv-armv7-unknown-linux-musleabihf.tar.gz.sha256) | </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this MR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box --- This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC42Mi4xIiwidXBkYXRlZEluVmVyIjoiNDAuNjIuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiUmVub3ZhdGUgQm90Il19-->
We've seen a few cases of uv.exe exiting with an exception code as its exit status and no user-visible output (#14563 in the field, and #13812 in CI). It seems that recent versions of Windows no longer show dialog boxes on access violations (what UNIX calls segfaults) or similar errors. Something is probably sent to Windows Error Reporting, and we can maybe sign up to get the crashes from Microsoft, but the user experience of seeing uv exit with no output is poor, both for end users and during development. While it's possible to opt out of this behavior or set up a debugger, this isn't the default configuration. (See https://superuser.com/q/1246626 for some pointers.)
In order to get some output on a crash, we need to install our own default handler for unhandled exceptions (or call all our code inside a Structured Exception Handling __try/__catch block, which is complicated on Rust). This is the moral equivalent of a segfault handler on Windows; the kernel creates a new stack frame and passes arguments to it with some processor state.
This commit adds a relatively simple exception handler that leans on Rust's own backtrace implementation and also displays some minimal information from the exception itself. This should be enough info to communicate that something went wrong and let us collect enough information to attempt to debug. There are also a handful of (non-Rust) open-source libraries for this like Breakpad and Crashpad (both from Google) and crashrpt.
The approach here, of using SetUnhandledExceptionFilter, seems to be the standard one taken by other such libraries. Crashpad also seems to try to use a newer mechanism for an out-of-tree DLL to report the crash: https://issues.chromium.org/issues/42310037
If we have serious problems with memory corruption, it might be worth adopting some third-party library that has already implemented this approach. (In general, the docs of other crash reporting libraries are worth skimming to understand how these things ought to work.)