fix(launcher): retry uv install steps to survive transient first-run 448 (Windows/OneDrive)#325
Merged
Merged
Conversation
On Windows with OneDrive Files-On-Demand, the cloud-filter driver (cldflt) can transiently fail uv's creation of the managed-Python minor-version junction with "untrusted mount point" (os error 448) while it engages a freshly created folder tree on the very first run. The same uv binary, flags, env, and folder succeed when run a moment later from a shell — it's a one-time race against the filter settling, not a deterministic block, and uv has no flag to skip the junction. Wrap the two uv install commands in a short, growing backoff retry (installStepAttempts) so a one-time failure self-heals instead of hard-aborting the user's first run — exactly when it bites. Retrying is cheap because uv caches its downloads. The retry logic is factored into a pure, unit-tested withRetry helper. Also pass --no-bin to `uv python install`: the launcher runs start_photomap from the tool venv directly, so there's no need for uv to drop a python3.12 shim into ~/.local/bin (which it can't manage on reinstall and is one more cross-folder write outside our runtime root). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-install-retry # Conflicts: # launcher/uv.go
lstein
added a commit
that referenced
this pull request
Jun 9, 2026
…ython junction (#326) The Windows/OneDrive first-run failure (os error 448, "untrusted mount point") comes from uv creating the managed-Python *minor-version directory junction*. OneDrive's cloud-filter driver (cldflt) blocks that junction creation on a freshly-created folder tree; it is deterministic on a clean machine, so the retry added in #325 cannot help (every attempt hits the same blocked junction). uv has no flag to skip the junction. Fix: don't let uv do a managed-Python *install* for the tool venv at all. We still run `uv python install` to download+extract the interpreter, but we treat a nonzero exit as success as long as the interpreter landed on disk (the junction is the only thing that fails, and we don't need it). We then point `uv tool install` at that interpreter via an explicit `--python <path>` — with UV_PYTHON_INSTALL_DIR unset, so uv treats it as an external interpreter and never attempts the junction. No junction is created, so the 448 cannot occur, regardless of timing or OneDrive state. Verified by hand on the affected machine. - uvEnv() no longer sets UV_PYTHON_INSTALL_DIR; ensurePython sets it only for the download step. uv's python-install output is captured and surfaced only if no usable interpreter is found, so the harmless 448 isn't shown. - Removes the now-ineffective retry machinery (withRetry/runUVRetry) from #325. - Keeps --no-bin (no python shim in ~/.local/bin) and #324's macOS Xcode warning. - Adds a unit test for findExtractedPython; updates the uvEnv test for the new contract. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On a Windows machine with OneDrive Files-On-Demand active, the very first run of the launcher aborted with:
After extensive isolation (same uv binary, flags, env, folder, elevation, cwd, and environment all tested), the failure proved to be a transient first-run race: OneDrive's cloud-filter driver (
cldflt) briefly returnsSTATUS_UNTRUSTED_MOUNT_POINT(448) on uv's managed-Python minor-version junction creation while the filter engages the freshly-created folder tree. Re-running the exact same uv command moments later — from bash, cmd, or even the Explorer shortcut — succeeds every time. uv has no flag to skip that junction (ensure_minor_version_linkis unconditional and fatal in uv's source), so we can't avoid creating it; we can only survive a one-time failure.Fix
Wrap the two
uvinstall commands in a short, growing-backoff retry (installStepAttempts = 3, 3s then 6s). A one-time 448 self-heals on the next attempt instead of hard-aborting the user's first run — the moment it actually bites. Retrying is cheap: uv caches downloads, so a retry reuses the already-fetched Python/wheels. The retry logic is factored into a pure, unit-testedwithRetry(attempts, backoff, fn)helper.Also pass
--no-bintouv python installso uv stops dropping apython3.12.exeshim into the user's~/.local/bin(which it can't manage on reinstall, and is one more cross-folder write outside our self-contained runtime root). The launcher runsstart_photomapfrom the tool venv directly and never needs Python onPATH.Tests
withRetry: recovers after transient failures, returns the last error when exhausted, stops on first success (no backoff). Pure helper — no real uv spawned.go build,go vet,go test,gofmt -lall clean.Notes
only-managedfix), which is already merged.🤖 Generated with Claude Code