henrygd/beszel · error
(%d) failed to fetch latest releases: %s
Error message
(%d) failed to fetch latest releases: %s
What it means
FetchLatestRelease queries the GitHub releases API (or a configured base URL). Go's http.Client does not treat non-2xx status codes as errors, so the library explicitly checks and returns this error containing the HTTP status code and the raw response body when the status is >= 400. It means the releases listing request was rejected by the server.
Source
Thrown at internal/ghupdate/ghupdate.go:260
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return nil, err
}
res, err := client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
rawBody, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}
// http.Client doesn't treat non 2xx responses as error
if res.StatusCode >= 400 {
return nil, fmt.Errorf(
"(%d) failed to fetch latest releases:\n%s",
res.StatusCode,
string(rawBody),
)
}
result := &release{}
if err := json.Unmarshal(rawBody, result); err != nil {
return nil, err
}
return result, nil
}
func downloadFile(
ctx context.Context,
client HttpClient,
url string,View on GitHub (pinned to b38fb7dafa)
Solutions
- Read the status and body in the error message: 403 usually means rate limiting — authenticate with a GITHUB_TOKEN or wait for the rate limit window to reset.
- Verify the configured owner/repo (or GitHubEnterprise base URL) actually exists and has releases.
- If a token is configured, confirm it is valid and not expired (401/404).
- Retry after checking GitHub status (https://www.githubstatus.com) if the status is 5xx.
Example fix
// before: unauthenticated requests get rate-limited
client := ghupdate.NewUpdater(...)
rel, err := client.FetchLatestRelease(ctx) // (403) failed to fetch latest releases: ...rate limit...
// after: provide an authenticated http client
httpClient := &http.Client{Transport: &authTransport{token: os.Getenv("GITHUB_TOKEN")}}
rel, err := clientWithHTTP(httpClient).FetchLatestRelease(ctx) Defensive patterns
Strategy: retry
Validate before calling
resp, err := http.Get(baseURL + "/rate_limit")
if err == nil {
defer resp.Body.Close()
// inspect remaining core requests before calling FetchLatestRelease
} Type guard
func isRateLimitErr(err error) bool {
return err != nil && strings.Contains(err.Error(), "(403)") && strings.Contains(err.Error(), "rate limit")
} Try / catch
rel, err := updater.FetchLatestRelease(ctx)
if err != nil {
var he interface{ Error() string }
if strings.Contains(err.Error(), "(403)") { // rate limited
time.Sleep(time.Until(resetTime)); rel, err = updater.FetchLatestRelease(ctx)
}
if err != nil { return fmt.Errorf("release check failed: %w", err) }
} Prevention
- Authenticate GitHub API requests with a token to raise rate limits.
- Cache the last release check and back off (don't poll every run).
- Validate owner/repo configuration on startup.
- Alert on 5xx statuses instead of retrying in a tight loop.
When it happens
Trigger: Calling FetchLatestRelease (called from update) when the releases endpoint responds 4xx/5xx — e.g. 404 for a nonexistent repo, 403 from GitHub API rate limiting, 401 from a bad token, or 5xx server errors.
Common situations: Hitting GitHub's unauthenticated rate limit (60 req/h) and getting 403 with a rate-limit JSON body; typo in the owner/repo configured for updates; a proxy or corporate firewall returning 4xx; GitHub incidents returning 5xx.
Related errors
- (%d) failed to send download file request
- http get: %w
- no websocket connection
- timeout creating session
- container inspect request failed: %s
AI-assisted analysis of henrygd/beszel@b38fb7dafa (2026-08-31).
Data as JSON: /api/errors/d2c43c285fef54ad.
Report an issue: GitHub.