{"record":{"id":"5154c34f8bbda121","repo":"MHSanaei/3x-ui","slug":"github-api-returned-status-d-s","errorCode":null,"errorMessage":"GitHub API returned status %d: %s","messagePattern":"GitHub API returned status (.+?): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/web/service/panel/panel.go","lineNumber":431,"sourceCode":"// fetchPanelRelease fetches a release from GitHub. An empty tag resolves the\n// latest stable release; a non-empty tag (e.g. dev-latest) resolves that tag.\nfunc fetchPanelRelease(tag string) (*service.Release, error) {\n\turl := \"https://api.github.com/repos/MHSanaei/3x-ui/releases/latest\"\n\tif tag != \"\" {\n\t\turl = \"https://api.github.com/repos/MHSanaei/3x-ui/releases/tags/\" + tag\n\t}\n\tclient := (&service.SettingService{}).NewProxiedHTTPClient(10 * time.Second)\n\treq, reqErr := http.NewRequestWithContext(context.Background(), http.MethodGet, url, nil)\n\tif reqErr != nil {\n\t\treturn nil, reqErr\n\t}\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"GitHub API returned status %d: %s\", resp.StatusCode, resp.Status)\n\t}\n\n\tvar release service.Release\n\tif err := json.NewDecoder(resp.Body).Decode(&release); err != nil {\n\t\treturn nil, err\n\t}\n\treturn &release, nil\n}\n\n// extractReleaseCommit reads the build commit recorded in the dev release: first\n// the `commit=<sha>` marker the CI writes into the body, falling back to the\n// tag's target commit.\nfunc extractReleaseCommit(release *service.Release) string {\n\tif m := releaseCommitRegex.FindStringSubmatch(release.Body); m != nil {\n\t\treturn strings.ToLower(m[1])\n\t}\n\tif isCommitSHA(release.TargetCommitish) {\n\t\treturn strings.ToLower(release.TargetCommitish)","sourceCodeStart":413,"sourceCodeEnd":449,"githubUrl":"https://github.com/MHSanaei/3x-ui/blob/ad32144c42455696ea9f14e12168beac3e25f5d2/internal/web/service/panel/panel.go#L413-L449","documentation":"Returned by fetchPanelRelease when the GitHub releases API responds with any status other than 200. The message includes both the numeric code and resp.Status. By far the most common cause is GitHub's unauthenticated rate limit (403 with 'API rate limit exceeded'); 404 means the requested tag does not exist (e.g. a dev-latest tag not yet published), 401 means a bad token.","triggerScenarios":"More than 60 unauthenticated requests/hour to api.github.com from the same IP (403); fetchPanelRelease(\"dev-latest\") when that tag has no release yet (404); GitHub incident (5xx); proxy blocking api.github.com.","commonSituations":"Panels on shared IPs (NAT cloud ranges) that exhaust the anonymous quota; checking for a dev release before CI has published it; automated update checks running too frequently.","solutions":["Wait for the rate-limit window to reset (up to 1 hour) or set GITHUB_TOKEN to raise the limit to 5000/h","For 404 on a specific tag, verify the release exists: curl -s https://api.github.com/repos/MHSanaei/3x-ui/releases/tags/<tag>","Check https://www.githubstatus.com for ongoing incidents and retry later","Confirm the configured HTTP proxy allows api.github.com"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if resp.StatusCode == http.StatusForbidden {\n    if reset := resp.Header.Get(\"X-RateLimit-Reset\"); reset != \"\" {\n        // compute wait time before retrying\n    }\n}\n","typeGuard":null,"tryCatchPattern":"var apiErr error\nfor attempt := 0; attempt < 3; attempt++ {\n    release, apiErr = fetchPanelRelease(tag)\n    if apiErr == nil || !strings.Contains(apiErr.Error(), \"status 403\") {\n        break\n    }\n    time.Sleep(backoff(attempt)) // honor X-RateLimit-Reset when present\n}\n","preventionTips":["Set GITHUB_TOKEN on hosts doing frequent update checks","Cache the latest-release result instead of polling per request","Treat 404 on /releases/tags/<tag> as 'tag not yet published', not a bug"],"tags":["github-api","rate-limit","network"],"backgroundTag":null,"analyzedSha":"ad32144c42455696ea9f14e12168beac3e25f5d2","analyzedAt":"2026-08-15T11:13:23.905Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}