MHSanaei/3x-ui · error

GitHub API error: %s

Error message

GitHub API error: %s

What it means

Returned by the release-list fetch (GetXrayVersions path) when the GitHub API answers non-200 AND the JSON body contains a non-empty "message" field — GitHub's standard error envelope. The message is surfaced verbatim, e.g. 'API rate limit exceeded for 1.2.3.4' or 'Bad credentials'. It exists because the caller expects an array of releases but GitHub returns an error object, which would otherwise fail confusingly during json.Unmarshal.

Source

Thrown at internal/web/service/server.go:798

	req, reqErr := http.NewRequestWithContext(context.Background(), http.MethodGet, XrayURL, nil)
	if reqErr != nil {
		return nil, reqErr
	}
	resp, err := s.settingService.NewProxiedHTTPClient(10 * time.Second).Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	// Check HTTP status code - GitHub API returns object instead of array on error
	if resp.StatusCode != http.StatusOK {
		bodyBytes, _ := io.ReadAll(resp.Body)
		var errorResponse struct {
			Message string `json:"message"`
		}
		if json.Unmarshal(bodyBytes, &errorResponse) == nil && errorResponse.Message != "" {
			return nil, fmt.Errorf("GitHub API error: %s", errorResponse.Message)
		}
		return nil, fmt.Errorf("GitHub API returned status %d: %s", resp.StatusCode, resp.Status)
	}

	buffer := bytes.NewBuffer(make([]byte, bufferSize))
	buffer.Reset()
	if _, err := buffer.ReadFrom(resp.Body); err != nil {
		return nil, err
	}

	var releases []Release
	if err := json.Unmarshal(buffer.Bytes(), &releases); err != nil {
		return nil, err
	}

	var versions []string
	for _, release := range releases {
		tagVersion := strings.TrimPrefix(release.TagName, "v")

View on GitHub (pinned to ad32144c42)

Solutions

  1. Read the message: 'rate limit' → wait for the hourly window reset or supply GITHUB_TOKEN; 'Bad credentials' → fix or remove the token
  2. Reduce the polling frequency of version checks
  3. Retry after the Retry-After / X-RateLimit-Reset window indicated by the API
Defensive patterns

Strategy: retry

Try / catch

versions, err := svc.GetXrayVersions()
if err != nil && strings.Contains(err.Error(), "rate limit") {
    // wait for X-RateLimit-Reset window or set GITHUB_TOKEN, then retry
}

Prevention

When it happens

Trigger: Unauthenticated quota exhausted (403 + rate-limit message); an invalid GITHUB_TOKEN (401 'Bad credentials'); requesting the XTLS/Xray-core releases list too often from a shared IP.

Common situations: Panels on cloud NAT IPs sharing the 60 req/h anonymous budget; update checks on a cron with short intervals; a revoked or typo'd token in the environment.

Related errors


AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15). Data as JSON: /api/errors/d85ba58adc6ef1ea. Report an issue: GitHub.