Skip to content

uvx not downloaded when uv version already matches, leaving bin/uvx dangling #9

Description

TLDR

_bootstrap_uv decides whether to download by checking uv's version only. If prefix/uv already matches the pinned version but prefix/uvx is missing, uvx is never fetched - yet setup.py still creates bin/uvx -> ../uvx, leaving a dangling symlink and a broken $..._UVX env var. Reported as an observation from an upgrade path, not a live outage.

Reproduction (confirmed)

$ # a prefix whose uv already matches the pin, but with no uvx
$ rm -f "$PREFIX/uvx" "$PREFIX/bin/uvx"
$ ./install.sh --prefix "$PREFIX" --python 3.14 --env-prefix NATTERBOX --isolated
  ✓ uv 0.10.12            <- download skipped
  ✓ bin/uvx → ../uvx      <- symlink created anyway

$ ls "$PREFIX/uvx"
ls: no such file or directory

$ source "$PREFIX/env.sh" && "$NATTERBOX_UVX" --version
bash: .../uvx: No such file or directory

The install reports success throughout. Nothing warns that uvx is missing.

Cause

install.sh _bootstrap_uv (and the equivalent block in install.ps1):

if [[ -x "$uv_bin" ]] && \
   [[ "$("$uv_bin" --version 2>/dev/null | awk '{print $2}')" == "$uv_version" ]]; then
    _msg "  ✓ uv $uv_version"; return
fi

The guard predates uvx (added in v0.10.0, #4) and was never extended to account for the second binary. _create_bin in setup.py then unconditionally symlinks bin/uvx, so a missing uvx becomes a dangling link rather than an error.

When it bites

Upgrading from a pre-v0.10.0 prefix (no uvx) to a version that pins the same uv release the prefix already has. The version check short-circuits, uvx is never downloaded, and the resulting install looks healthy but has a broken uvx.

Not currently reachable via the Atlas bootstrap - v0.9.2 pins uv 0.10.6 and v0.11.0 pins 0.10.12, so uv is re-downloaded and uvx arrives with it (verified). It becomes reachable the moment a distro bump keeps uv_version unchanged, which is a perfectly normal thing to do.

Suggested fix

Extend the skip condition to require both binaries, so a missing uvx forces the download:

if [[ -x "$uv_bin" ]] && [[ -x "${prefix}/uvx" ]] && \
   [[ "$("$uv_bin" --version ...)" == "$uv_version" ]]; then

Same change in install.ps1 for uv.exe / uvx.exe. Optionally, have _create_bin warn (or fail) when a symlink target does not exist - a broken bin/ entry is never a valid outcome.

Reversibility

Two-way door - one guard condition per installer script.

Note

Found while bumping the Atlas install-dev-machine pin to v0.11.0 (redmatter/atlas#677). Filing rather than fixing, since it is outside that task's scope.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions