gastownhall/beads · warning
pypi api returned status %d
Error message
pypi api returned status %d
What it means
fetchLatestPyPIVersion queries the PyPI JSON API for the latest beads plugin version. If the HTTP response status is anything other than 200 OK, it returns this error with the actual status code, aborting the version lookup.
Source
Thrown at cmd/bd/doctor/claude.go:621
Timeout: 5 * time.Second,
}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return "", err
}
// Set User-Agent
req.Header.Set("User-Agent", "beads-cli-doctor")
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("pypi api returned status %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
var data struct {
Info struct {
Version string `json:"version"`
} `json:"info"`
}
if err := json.Unmarshal(body, &data); err != nil {
return "", err
}
return data.Info.Version, nilView on GitHub (pinned to 71377f2769)
Solutions
- Retry later — transient 429/5xx from PyPI usually resolves on its own
- Check the package exists at pypi.org/pypi/<package>/json (404 means renamed/removed)
- Verify network/proxy settings (HTTPS_PROXY) and that a corporate proxy isn't injecting error responses
- Check status.pypi.org for ongoing incidents; plugin update checking is non-fatal, so the rest of bd doctor still works
Example fix
// before $ curl -i https://pypi.org/pypi/beads-plugin/json # HTTP 404 // after # package renamed; check correct name $ curl -i https://pypi.org/pypi/beads/json # HTTP 200
Defensive patterns
Strategy: retry
Validate before calling
import "net/http"
func pypiReachable(pkg string) error {
resp, err := http.Get("https://pypi.org/pypi/" + pkg + "/json")
if err != nil { return err }
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("pypi status %d", resp.StatusCode)
}
return nil
} Try / catch
ver, err := fetchLatestPyPIVersion(pkg)
if err != nil {
var statusErr interface{ Error() string }
_ = statusErr
log.Printf("latest-version lookup skipped: %v", err) // non-fatal
return "unknown", nil
}
// retry with backoff on 429/5xx before giving up Prevention
- Treat plugin update checks as best-effort; don't fail workflows on them
- Respect PyPI rate limits (429) with exponential backoff
- Pin expected versions instead of relying on live lookups in CI
- Check proxy/firewall rules that could return 403/502 for pypi.org
When it happens
Trigger: fetchLatestPyPIVersion (during Claude plugin update checks in `bd doctor`) when the PyPI API responds with a non-200 status — 404 if the package name is wrong/renamed, 429 rate-limit, 5xx server errors — at cmd/bd/doctor/claude.go:621.
Common situations: Corporate proxies or captive portals returning error pages (403/502); PyPI outages or rate limiting; the package being renamed or unpublished; DNS resolving to a wrong endpoint.
Related errors
- failed to list projects: %w
- request failed (attempt %d/%d): %w
- failed to fetch issue %d: %w
- failed to fetch milestones: %w
- failed to fetch milestone by IID %d: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/68d96e8b05f1ab9a.
Report an issue: GitHub.