siyuan-note/siyuan · error
get GitHub releases failed
Error message
get GitHub releases failed: %d
What it means
fetchGitHubReleases performs a GET on the GitHub releases API (api.github.com/repos/siyuan-note/siyuan/releases). When the HTTP request succeeds transport-wise but GitHub replies with a non-200 status, the call fails with 'get GitHub releases failed: <status>'. This surfaces GitHub-side rejections such as rate limiting or API version problems.
Solutions
- Check the status code in the log: 403 means rate-limited — wait for the limit window to reset or use authenticated network egress
- Retry with force=false to use the 6-hour cached release list if one exists
- Test the URL https://api.github.com/repos/siyuan-note/siyuan/releases manually from the affected machine to inspect the actual response
- Switch to the stable update channel, which uses the cloud Rhy endpoint instead of the GitHub API, or check for updates later
Defensive patterns
Strategy: retry
Validate before calling
resp, err := http.Get(githubReleasesURL)
if err != nil || resp.StatusCode == 403 {
// likely rate limited: delay or skip the check
} Try / catch
releases, err := fetchGitHubReleases(ctx)
var rateLimited bool
if err != nil && strings.Contains(err.Error(), "403") {
rateLimited = true // back off exponentially, use cache
} Prevention
- Respect the unauthenticated GitHub API limit (60 req/h per IP); rely on the built-in 6h cache and avoid force=true in loops
- Serve shared/CI environments with authenticated egress or a caching proxy
- Check the logged status code: 403 = rate limit, 5xx = GitHub-side
- Fall back to the stable channel when GitHub API access is unreliable
When it happens
Trigger: Any update check on a non-stable channel when the GitHub API responds 403 (rate limit exhausted for the egress IP), 404, 5xx, or any non-200 status during fetchGitHubReleases.
Common situations: CI servers or shared NAT egress hitting GitHub's unauthenticated 60 req/hour rate limit; corporate proxies returning 403/502; GitHub API incidents/outages; blocked network regions returning intermediary status codes.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- authentication probe returned HTTP " + response.status
- boot progress request returned HTTP " + response.status
- discover OIDC provider failed
- download custom emoji failed
- download custom emoji failed with status
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/caa9cc1aecf80f3a.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/updater_release.go:247
return nil, err
}
return value.([]*githubRelease), nil
}
func fetchGitHubReleases(ctx context.Context) ([]*githubRelease, error) {
releases := []*githubRelease{}
request := httpclient.NewCloudRequest30s().
SetContext(ctx).
SetHeader("Accept", "application/vnd.github+json").
SetHeader("X-GitHub-Api-Version", "2022-11-28").
SetSuccessResult(&releases)
response, err := request.Get(githubReleasesURL)
if err != nil {
logging.LogErrorf("get GitHub releases failed: %s", err)
return nil, err
}
if 200 != response.StatusCode {
err = fmt.Errorf("get GitHub releases failed: %d", response.StatusCode)
logging.LogError(err.Error())
return nil, err
}
if 0 == len(releases) {
return nil, errors.New("GitHub releases are empty")
}
githubReleasesLock.Lock()
cachedGitHubReleases = releases
githubReleasesCacheTime = time.Now().Unix()
githubReleasesLock.Unlock()
return releases, nil
}
func selectGitHubRelease(releases []*githubRelease, channel string) *githubRelease {
var selected *githubRelease
for _, release := range releases {
if nil == release || release.Draft || !isReleaseAllowed(channel, release.TagName) {View on GitHub (pinned to 9f775e8a12)