Devolutions/UniGetUI · error · HttpRequestException
PyPI simple index returned {(int)response.StatusCode} {respo
Error message
PyPI simple index returned {(int)response.StatusCode} {response.ReasonPhrase} What it means
Pip's index loader throws HttpRequestException when the GET to https://pypi.org/simple/ (the ~38 MB PyPI simple index, cached 24h) returns a non-success status. The status code and reason phrase are embedded in the message. This blocks pip package search until a successful download/cache.
Source
Thrown at src/UniGetUI.PackageEngine.Managers.Pip/Pip.cs:201
string[] cached = File.ReadAllLines(cacheFile);
if (cached.Length > 0)
{
lock (_cacheLock) { _cachedNames = cached; _cacheTimestamp = File.GetLastWriteTime(cacheFile); }
return cached;
}
logger.Error("PyPI index file cache was empty, re-downloading...");
}
// Download fresh index
logger.Log("Downloading PyPI simple index (one-time ~38 MB download, cached for 24 h)...");
using HttpClient client = new(CoreTools.GenericHttpClientParameters);
client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString);
client.DefaultRequestHeaders.Add("Accept", "application/vnd.pypi.simple.v1+json");
using var request = new HttpRequestMessage(HttpMethod.Get, "https://pypi.org/simple/");
using HttpResponseMessage response = client.Send(request);
if (!response.IsSuccessStatusCode)
throw new HttpRequestException($"PyPI simple index returned {(int)response.StatusCode} {response.ReasonPhrase}");
string json = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
string[] names = ParseSimpleIndexProjectNames(json);
logger.Log($"Downloaded {names.Length} package names from PyPI");
// Update memory cache before attempting file write so searches work even if file write fails
lock (_cacheLock) { _cachedNames = names; _cacheTimestamp = DateTime.Now; }
try
{
Directory.CreateDirectory(Path.GetDirectoryName(cacheFile)!);
File.WriteAllLines(cacheFile, names);
}
catch (Exception e)
{
logger.Error($"Could not write PyPI index file cache to {cacheFile}: {e.Message}");
}View on GitHub (pinned to 9b1d7d0eab)
Solutions
- Retry after a short delay (the index is cached; transient failures clear on next refresh).
- Verify network/proxy reachability to https://pypi.org/simple/ from the host.
- If a stale cache file exists, the loader falls back to it only if non-empty; ensure pip proxy env (PIP_INDEX_URL/HTTP(S)_PROXY) is correct.
Example fix
// before: single shot throws on non-2xx
using HttpResponseMessage response = client.Send(request);
if (!response.IsSuccessStatusCode)
throw new HttpRequestException($"PyPI simple index returned {(int)response.StatusCode} {response.ReasonPhrase}");
// after: one bounded retry
for (int i = 0; i < 2; i++)
{
using var resp = client.Send(request.Clone());
if (resp.IsSuccessStatusCode) { /* parse */ return; }
if (i == 1) throw new HttpRequestException($"PyPI simple index returned {(int)resp.StatusCode} {resp.ReasonPhrase}");
} Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight reachability to pypi.org before the heavy download.
using var ping = await client.GetAsync("https://pypi.org/simple/", HttpCompletionOption.ResponseHeadersRead);
if (!ping.IsSuccessStatusCode) Logger.Warn($"PyPI not reachable: {ping.StatusCode}"); Try / catch
int attempts = 0;
HttpStatusCode? last = null;
while (attempts < 3)
{
try { /* download + parse index */ return; }
catch (HttpRequestException ex) { last = ParseStatus(ex.Message); attempts++; await Task.Delay(TimeSpan.FromSeconds(5 * attempts)); }
}
throw new HttpRequestException($"PyPI index unavailable after retries (last={last})"); Prevention
- Keep the 24h cache so transient PyPI failures don't break search immediately.
- Ensure PIP_INDEX_URL/HTTP(S)_PROXY point at reachable PyPI mirrors.
- Retry with backoff on 429/5xx rather than failing the first search.
When it happens
Trigger: PyPI returns 4xx/5xx for the simple-index request: rate limiting (429), maintenance (5xx), DNS/proxy failure surfaced as a non-success, or a transient network blip.
Common situations: Corporate proxy/firewall blocking pypi.org; PyPI rate-limiting; transient outage; misconfigured proxy argument to pip.
Related errors
- PyPI simple index returned 0 packages — response may be malf
- The updater download server returned an invalid partial cont
- The updater download server returned partial content with a
- GitHub request failed with HTTP {(int)response.StatusCode} (
- Null response for package {packageId}
AI-assisted analysis of Devolutions/UniGetUI@9b1d7d0eab (2026-08-13).
Data as JSON: /api/errors/02d1720a49af54f6.
Report an issue: GitHub.