Skip Windows Python interpreters that return a broken MSIX package code (#14636)

Currently we treat all spawn failures as fatal, because they indicate a
broken interpreter. In this case, I think we should just skip these
broken interpreters — though I don't know the root cause of why it's
broken yet.

Closes https://github.com/astral-sh/uv/issues/14637
See
1394758502
This commit is contained in:
Zanie Blue 2025-07-15 16:47:35 -05:00 committed by GitHub
parent ab2bd0179b
commit 863e73a841
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 35 additions and 4 deletions

View file

@ -884,6 +884,14 @@ impl Error {
);
false
}
#[cfg(windows)]
InterpreterError::CorruptWindowsPackage { path, err } => {
debug!(
"Skipping bad interpreter at {} from {source}: {err}",
path.display()
);
false
}
InterpreterError::NotFound(path)
| InterpreterError::BrokenSymlink(BrokenSymlink { path, .. }) => {
// If the interpreter is from an active, valid virtual environment, we should

View file

@ -34,6 +34,9 @@ use crate::{
VirtualEnvironment,
};
#[cfg(windows)]
use windows_sys::Win32::Foundation::{APPMODEL_ERROR_NO_PACKAGE, ERROR_CANT_ACCESS_FILE};
/// A Python executable and its associated platform markers.
#[derive(Debug, Clone)]
pub struct Interpreter {
@ -760,6 +763,13 @@ pub enum Error {
#[source]
err: io::Error,
},
#[cfg(windows)]
#[error("Failed to query Python interpreter at `{path}`")]
CorruptWindowsPackage {
path: PathBuf,
#[source]
err: io::Error,
},
#[error("{0}")]
UnexpectedResponse(UnexpectedResponseError),
#[error("{0}")]
@ -872,10 +882,23 @@ impl InterpreterInfo {
.arg("-c")
.arg(script)
.output()
.map_err(|err| Error::SpawnFailed {
path: interpreter.to_path_buf(),
err,
})?;
.map_err(
|err| match err.raw_os_error().and_then(|code| u32::try_from(code).ok()) {
// These error codes are returned if the Python interpreter is a corrupt MSIX
// package, which we want to differentiate from a typical spawn failure.
#[cfg(windows)]
Some(APPMODEL_ERROR_NO_PACKAGE | ERROR_CANT_ACCESS_FILE) => {
Error::CorruptWindowsPackage {
path: interpreter.to_path_buf(),
err,
}
}
_ => Error::SpawnFailed {
path: interpreter.to_path_buf(),
err,
},
},
)?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();