make the error message clearer when running distroless containers#13549
make the error message clearer when running distroless containers#13549oconnor663 merged 7 commits intomainfrom
Conversation
|
The direct way to test this is to rebuild our docker image and run a command in it, though that takes a long time: An more direct way to create the same condition is to use an empty I don't love this run-on error message. My first instinct was to use two or three separate Pie-in-the-sky-new-guy thought: Would it be nice/useful if our errors supported some sort of What do you think about adding a test for this? Do we have any integration tests for the Docker image? My quick read of |
|
My intuition is to split the error into two errors: A source error, the current one, and a nicer one that wraps it that says something like We can also add an outer error that says something like "Failed to install a managed Python interpreter" to make it more clear what component failed and how to work around this (provide a system (or nix?) interpreter or install a Python yourself). In this case it's not too helpful since the problem is usually you're in the wrong docker container, but I generally try contextualize errors by component, it also helps when users are sharing error traces in bug reports. A trick that we sometimes use is to make a line break and add a Can we add guidance in the error message what the user should do, e.g. if they are on nix?
One option is to use the musl build we already have in CI and mount it into a distroless docker and capture the output. This is complicated though, and for this error path may not be worth the complexity, manual testing might be sufficient. |
Yeah I agree this is another thing I'd expect to see here. We should add one or more layers that elucidate why we're trying to read this thing as well. |
|
I don't think we need to add test coverage for this, a manual check is sufficient for now. We're not really set up to snapshot the output in a meaningful way. It might be a nice thing to have a harness for integration tests in the future so we can capture things like this (maybe open an issue to track that?) |
|
|
One way to test this logic on an existing binary, without rebuilding anything, is to pick a different path for the ELF interpreter inside the chroot and use $ mkdir chroot
$ patchelf ~/.local/bin/uv --set-interpreter /ld.so --output chroot/uv
$ cp "$(patchelf --print-interpreter ~/.local/bin/uv)" chroot/ld.so
$ ldd ~/.local/bin/uv | sed -n 's/.*=> \(.*\) .*/\1/p' | xargs -I_ rsync -aLR _ chroot
$ busybox unshare -Urm chroot chroot /uv run python
error: Could not read ELF interpreter from any of the following paths: /bin/sh, /usr/bin/env, /bin/dash, /bin/ls
The Also, because we aren't currently looking for the interpreter itself, just these files, you can reproduce the current behavior without even calling patchelf, just copy the ELF interpreter under its original name into the chroot: $ rm -rf chroot
$ mkdir chroot
$ cp ~/.local/bin/uv chroot/uv
$ rsync -aLR "$(patchelf --print-interpreter ~/.local/bin/uv)" chroot
$ ldd ~/.local/bin/uv | sed -n 's/.*=> \(.*\) .*/\1/p' | xargs -I_ rsync -aLR _ chroot
$ busybox unshare -Urm chroot chroot /uv run python
error: Could not read ELF interpreter from any of the following paths: /bin/sh, /usr/bin/env, /bin/dash, /bin/ls(This is a bug - this chroot has a working ELF interpreter and python-build-standalone will work - but we can tackle that separately from improving the error messages of the current logic.) |
|
Fwiw you can build a statically linked uv through musl and put that into a docker container (Using |
|
Brief check-in: I wound up spending the last couple days on #13583. I'm going to put out a second iteration on that PR and get back to this one tomorrow. Edit: This is on top of my plate for tomorrow (Friday) morning. |
Previously you could generate a confusing warning like this: ``` $ docker run ghcr.io/astral-sh/uv run python error: Could not read ELF interpreter from any of the following paths: /bin/sh, /usr/bin/env, /bin/dash, /bin/ls ``` Now the error message is better: ``` error: Failed to find a managed Python installation matching the current platform Caused by: Failed to determine the current platform Caused by: Failed to find any common binaries (/bin/sh, /usr/bin/env, /bin/dash, /bin/ls) ``` See #8635.
f6bf535 to
1ec4975
Compare
|
Ok this is ready for another look. Here's what the error looks like now: This is my first time working with |
|
There's a second |
Co-authored-by: konsti <[email protected]>
crates/uv-python/src/downloads.rs
Outdated
| #[error("A mirror was provided via `{0}`, but the URL does not match the expected format: {0}")] | ||
| Mirror(&'static str, &'static str), | ||
| #[error(transparent)] | ||
| #[error("Failed to determine the current platform")] |
There was a problem hiding this comment.
Copy/pasting this in two places makes me wonder if there's an easy way to make the LibcDetectionError apply this annotation itself. I assume not without changing it into a struct with an internal "error kind"?
There was a problem hiding this comment.
thiserror at least doesn't support it, I think that's a limitation because every .source() needs a type and we'd need two type for the LibcDetectionError error message and the variant error message, but we only have one type.
There was a problem hiding this comment.
Ah, I wasn't even thinking about the .source() representation, just prefixing the string representation of all variants of the enum with "Failed to find the current platform: (...)" or something like that.
There was a problem hiding this comment.
Should this be "Failed to determine the libc used on the current platform"? This message seems too generic for a libc-detection specific problem.
There was a problem hiding this comment.
I'd push the libc part down to the most detailed error, I don't expect Python devs to know about libc flavors.
There was a problem hiding this comment.
As structured, it needs to be present here or it's too broad / inaccurate. I also don't expect devs to know about libc flavors, but there should be an error above this explaining why we're looking for it. I'm also fine with it being structured differently.
geofft
left a comment
There was a problem hiding this comment.
I'm going to step back from this review so that you're not blocked on me being around to review, but in general it looks like what you have here is a definite improvement on the status quo, and getting much farther would require reworking the actual detection logic.
crates/uv-python/src/discovery.rs
Outdated
| /// An error was encountered when interacting with a managed Python installation. | ||
| /// An error was encountered while trying to find a managed Python installation matching the | ||
| /// current platform. | ||
| #[error("Failed to find a managed Python installation")] |
There was a problem hiding this comment.
I probably need to see the actual errors as they would be output to understand what's going on here, so feel free to disregard this, but - "Failed to find a managed Python installation" reads to me as that we were expecting something to already be installed, and it wasn't installed. I think this error is saying that it failed to find a distribution (though I hate that word, it's overloaded) that is available to be installed, that matches the current platform, right?
"Failed to find a compatible managed Python version" maybe?
There was a problem hiding this comment.
This is in the Discovery enum so it should be correct as-written?
I'm more confused about why this isn't a ManagedPython enum member if it's ManagedPython-specific?
There was a problem hiding this comment.
I think this from / source split for managed Python errors is pretty awkward here.
There was a problem hiding this comment.
@geofft I don't know if we're necessarily expecting something to be installed, but this error occurs as we're looking at the versions that are already installed and filtering for the ones that are compatible with the current platform. (Presumably if we didn't find anything we would go on to try to download something, but we don't make it that far.) There's a piece of machinery called Error::is_critical involved here, where certain expected errors like "we failed to invoke that interpreter" are considered non-critical (because it's presumably just not compatible and we should try others), but this libc error isn't one of those expected cases.
Co-authored-by: Zanie Blue <[email protected]>
|
@zanieb I just pushed the |
Co-authored-by: Zanie Blue <[email protected]>
|
Committed @zanieb's wording change and updated the PR description. |
This MR contains the following updates: | Package | Update | Change | |---|---|---| | [astral-sh/uv](https://github.com/astral-sh/uv) | patch | `0.7.7` -> `0.7.13` | 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.7.13`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0713) [Compare Source](astral-sh/uv@0.7.12...0.7.13) ##### Python - Add Python 3.14.0b2 - Add Python 3.13.5 - Fix stability of `uuid.getnode` on 3.13 See the [`python-build-standalone` release notes](https://github.com/astral-sh/python-build-standalone/releases/tag/20250612) for more details. ##### Enhancements - Download versions in `uv python pin` if not found ([#​13946](astral-sh/uv#13946)) - Use TTY detection to determine if SIGINT forwarding is enabled ([#​13925](astral-sh/uv#13925)) - Avoid fetching an exact, cached Git commit, even if it isn't locked ([#​13748](astral-sh/uv#13748)) - Add `zstd` and `deflate` to `Accept-Encoding` ([#​13982](astral-sh/uv#13982)) - Build binaries for riscv64 ([#​12688](astral-sh/uv#12688)) ##### Bug fixes - Check if relative URL is valid directory before treating as index ([#​13917](astral-sh/uv#13917)) - Ignore Python discovery errors during `uv python pin` ([#​13944](astral-sh/uv#13944)) - Do not allow `uv add --group ... --script` ([#​13997](astral-sh/uv#13997)) ##### Preview changes - Build backend: Support namespace packages ([#​13833](astral-sh/uv#13833)) ##### Documentation - Add 3.14 to the supported platform reference ([#​13990](astral-sh/uv#13990)) - Add an `llms.txt` to uv ([#​13929](astral-sh/uv#13929)) - Add supported macOS version to the platform reference ([#​13993](astral-sh/uv#13993)) - Update platform support reference to include Python implementation list ([#​13991](astral-sh/uv#13991)) - Update pytorch.md ([#​13899](astral-sh/uv#13899)) - Update the CLI help and reference to include references to the Python bin directory ([#​13978](astral-sh/uv#13978)) ### [`v0.7.12`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0712) [Compare Source](astral-sh/uv@0.7.11...0.7.12) ##### Enhancements - Add `uv python pin --rm` to remove `.python-version` pins ([#​13860](astral-sh/uv#13860)) - Don't hint at versions removed by `excluded-newer` ([#​13884](astral-sh/uv#13884)) - Add hint to use `tool.uv.environments` on resolution error ([#​13455](astral-sh/uv#13455)) - Add hint to use `tool.uv.required-environments` on resolution error ([#​13575](astral-sh/uv#13575)) - Improve `python pin` error messages ([#​13862](astral-sh/uv#13862)) ##### Bug fixes - Lock environments during `uv sync`, `uv add` and `uv remove` to prevent race conditions ([#​13869](astral-sh/uv#13869)) - Add `--no-editable` to `uv export` for `pylock.toml` ([#​13852](astral-sh/uv#13852)) ##### Documentation - List `.gitignore` in project init files ([#​13855](astral-sh/uv#13855)) - Move the pip interface documentation into the concepts section ([#​13841](astral-sh/uv#13841)) - Remove the configuration section in favor of concepts / reference ([#​13842](astral-sh/uv#13842)) - Update Git and GitHub Actions docs to mention `gh auth login` ([#​13850](astral-sh/uv#13850)) ##### Preview - Fix directory glob traversal fallback preventing exclusion of all files ([#​13882](astral-sh/uv#13882)) ### [`v0.7.11`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0711) [Compare Source](astral-sh/uv@0.7.10...0.7.11) ##### Python - Add Python 3.14.0b1 - Add Python 3.13.4 - Add Python 3.12.11 - Add Python 3.11.13 - Add Python 3.10.18 - Add Python 3.9.23 ##### Enhancements - Add Pyodide support ([#​12731](astral-sh/uv#12731)) - Better error message for version specifier with missing operator ([#​13803](astral-sh/uv#13803)) ##### Bug fixes - Downgrade `reqwest` and `hyper-util` to resolve connection reset errors over IPv6 ([#​13835](astral-sh/uv#13835)) - Prefer `uv`'s binary's version when checking if it's up to date ([#​13840](astral-sh/uv#13840)) ##### Documentation - Use "terminal driver" instead of "shell" in `SIGINT` docs ([#​13787](astral-sh/uv#13787)) ### [`v0.7.10`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0710) [Compare Source](astral-sh/uv@0.7.9...0.7.10) ##### Enhancements - Add `--show-extras` to `uv tool list` ([#​13783](astral-sh/uv#13783)) - Add dynamically generated sysconfig replacement mappings ([#​13441](astral-sh/uv#13441)) - Add data locations to install wheel logs ([#​13797](astral-sh/uv#13797)) ##### Bug fixes - Avoid redaction of placeholder `git` username when using SSH authentication ([#​13799](astral-sh/uv#13799)) - Propagate credentials to files on devpi indexes ending in `/+simple` ([#​13743](astral-sh/uv#13743)) - Restore retention of credentials for direct URLs in `uv export` ([#​13809](astral-sh/uv#13809)) ### [`v0.7.9`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#079) [Compare Source](astral-sh/uv@0.7.8...0.7.9) ##### Python The changes reverted in [0.7.8](#​078) have been restored. See the [`python-build-standalone` release notes](https://github.com/astral-sh/python-build-standalone/releases/tag/20250529) for more details. ##### Enhancements - Improve obfuscation of credentials in URLs ([#​13560](astral-sh/uv#13560)) - Allow running non-default Python implementations via `uvx` ([#​13583](astral-sh/uv#13583)) - Add `uvw` as alias for `uv` without console window on Windows ([#​11786](astral-sh/uv#11786)) - Allow discovery of x86-64 managed Python builds on macOS ([#​13722](astral-sh/uv#13722)) - Differentiate between implicit vs explicit architecture requests ([#​13723](astral-sh/uv#13723)) - Implement ordering for Python architectures to prefer native installations ([#​13709](astral-sh/uv#13709)) - Only show the first match per platform (and architecture) by default in `uv python list` ([#​13721](astral-sh/uv#13721)) - Write the path of the parent environment to an `extends-environment` key in the `pyvenv.cfg` file of an ephemeral environment ([#​13598](astral-sh/uv#13598)) - Improve the error message when libc cannot be found, e.g., when using the distroless containers ([#​13549](astral-sh/uv#13549)) ##### Performance - Avoid rendering info log level ([#​13642](astral-sh/uv#13642)) - Improve performance of `uv-python` crate's manylinux submodule ([#​11131](astral-sh/uv#11131)) - Optimize `Version` display ([#​13643](astral-sh/uv#13643)) - Reduce number of reference-checks for `uv cache clean` ([#​13669](astral-sh/uv#13669)) ##### Bug fixes - Avoid reinstalling dependency group members with `--all-packages` ([#​13678](astral-sh/uv#13678)) - Don't fail direct URL hash checking with dependency metadata ([#​13736](astral-sh/uv#13736)) - Exit early on `self update` if global `--offline` is set ([#​13663](astral-sh/uv#13663)) - Fix cases where the uv lock is incorrectly marked as out of date ([#​13635](astral-sh/uv#13635)) - Include pre-release versions in `uv python install --reinstall` ([#​13645](astral-sh/uv#13645)) - Set `LC_ALL=C` for git when checking git worktree ([#​13637](astral-sh/uv#13637)) - Avoid rejecting Windows paths for remote Python download JSON targets ([#​13625](astral-sh/uv#13625)) ##### Preview - Add `uv add --bounds` to configure version constraints ([#​12946](astral-sh/uv#12946)) ##### Documentation - Add documentation about Python versions to Tools concept page ([#​7673](astral-sh/uv#7673)) - Add example of enabling Dependabot ([#​13692](astral-sh/uv#13692)) - Fix `exclude-newer` date format for persistent configuration files ([#​13706](astral-sh/uv#13706)) - Quote versions variables in GitLab documentation ([#​13679](astral-sh/uv#13679)) - Update Dependabot support status ([#​13690](astral-sh/uv#13690)) - Explicitly specify to add a new repo entry to the repos list item in the `.pre-commit-config.yaml` ([#​10243](astral-sh/uv#10243)) - Add integration with marimo guide ([#​13691](astral-sh/uv#13691)) - Add pronunciation to README ([#​5336](astral-sh/uv#5336)) ### [`v0.7.8`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#078) [Compare Source](astral-sh/uv@0.7.7...0.7.8) ##### Python We are reverting most of our Python changes from `uv 0.7.6` and `uv 0.7.7` due to a miscompilation that makes the Python interpreter behave incorrectly, resulting in spurious type-errors involving str. This issue seems to be isolated to x86\_64 Linux, and affected at least Python 3.12, 3.13, and 3.14. The following changes that were introduced in those versions of uv are temporarily being reverted while we test and deploy a proper fix for the miscompilation: - Add Python 3.14 on musl - free-threaded Python on musl - Add Python 3.14.0a7 - Statically link `libpython` into the interpreter on Linux for a significant performance boost See [the issue for details](astral-sh/uv#13610). ##### Documentation - Remove misleading line in pin documentation ([#​13611](astral-sh/uv#13611)) </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:eyJjcmVhdGVkSW5WZXIiOiI0MC4yNi4xIiwidXBkYXRlZEluVmVyIjoiNDAuNTEuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiUmVub3ZhdGUgQm90Il19-->
Previously you could generate a confusing warning like this:
Now the error message is better (updated):
See #8635.