Self-Healing CI: Auto-Retrying a uv Failed to Fetch from PyPI
uv reporting "Failed to fetch" against pypi.org hit a transport failure, not a missing distribution: the same resolution succeeds on a retry.
The problem
A uv install or sync fails while reaching pypi.org or files.pythonhosted.org. The requirement is valid and the version exists. uv resolves and downloads fast and in parallel, so a brief network interruption lands as a hard failure rather than being absorbed.
error: Failed to fetch: `https://pypi.org/simple/numpy/`Why it happens
uv is aggressively parallel by design, which is most of its speed advantage. The same parallelism means a short outage is more likely to intersect at least one in-flight request.
The message names the URL it could not reach rather than a package constraint, which is the tell that this is transport and not resolution. A genuinely unsatisfiable requirement fails with a resolution error naming the constraint.
The manual fix
Manual mitigations for a uv fetch failure:
- Re-run the command to retry the fetch.
- Set a longer HTTP timeout so a slow response is waited out rather than abandoned.
- Point uv at an internal index so CI does not depend on the public endpoint.
UV_HTTP_TIMEOUT=60 uv pip install -r requirements.txtHow this gets automated
uv writes these failures to stderr with the URL in the frame, which makes them cheap to recognize and safe to act on: a fetch failure against an index host is transport by definition. A self-healing pipeline retries the whole step with a short backoff, which is the right granularity here because uv resolves quickly enough that repeating the work costs little compared to failing the job.