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, nil

View on GitHub (pinned to 71377f2769)

Solutions

  1. Retry later — transient 429/5xx from PyPI usually resolves on its own
  2. Check the package exists at pypi.org/pypi/<package>/json (404 means renamed/removed)
  3. Verify network/proxy settings (HTTPS_PROXY) and that a corporate proxy isn't injecting error responses
  4. 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

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


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/68d96e8b05f1ab9a. Report an issue: GitHub.