siyuan-note/siyuan · error

get GitHub releases failed: %d

Error message

get GitHub releases failed: %d

What it means

Returned by fetchGitHubReleases(ctx) when the GitHub API responds with a status code other than 200. The numeric status is embedded in the message. The most common cause is 403 (rate limit) since the GitHub releases endpoint is unauthenticated. The error is logged via logging.LogError before returning.

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 251596fc0d)

Solutions

  1. Wait for the rate-limit window to reset (check X-RateLimit-Reset header) and retry; the cache (6h, githubAPIReleaseCacheSeconds) reduces repeated calls.
  2. Avoid force=true refreshes in loops — they bypass the cache and burn quota.
  3. Switch to the stable channel, which uses the rhy cloud endpoint and does not hit the GitHub API.
  4. If behind a shared NAT, consider routing GitHub API traffic through a distinct egress IP.
Defensive patterns

Strategy: retry

Try / catch

// Retry with backoff; respect GitHub rate limits.
var releases []*githubRelease
for attempt := 0; attempt < 3; attempt++ {
    rel, err := getGitHubReleases(ctx, attempt == 0)
    if err == nil {
        releases = rel
        break
    }
    if !strings.Contains(err.Error(), "get GitHub releases failed") {
        break // different error; don't retry blindly
    }
    time.Sleep(time.Duration(1<<attempt) * time.Minute)
}

Prevention

When it happens

Trigger: GitHub API returns 403 due to unauthenticated rate limiting (60 requests/hour per IP, shared across users behind a NAT/corporate proxy). 5xx during a GitHub outage. 304/other non-200 responses. A proxy returning an unexpected status.

Common situations: Many machines behind one public IP (office, CI, NAT) exhausting the 60/hour anonymous quota. GitHub incident. Corporate proxy intercepting api.github.com. Repeated force=true refreshes burning the quota.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/caa9cc1aecf80f3a. Report an issue: GitHub.