{"record":{"id":"1d04b4a98b09a8b1","repo":"MHSanaei/3x-ui","slug":"download-panel-updater-unexpected-http-d","errorCode":null,"errorMessage":"download panel updater: unexpected HTTP %d","messagePattern":"download panel updater: unexpected HTTP (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/web/service/panel/panel.go","lineNumber":369,"sourceCode":"func releaseUpdateSlot() {\n\tupdateMu.Lock()\n\tupdateRunning = false\n\tupdateMu.Unlock()\n}\n\nfunc downloadPanelUpdater() (string, error) {\n\tclient := (&service.SettingService{}).NewProxiedHTTPClient(15 * time.Second)\n\treq, reqErr := http.NewRequestWithContext(context.Background(), http.MethodGet, panelUpdaterURL, nil)\n\tif reqErr != nil {\n\t\treturn \"\", fmt.Errorf(\"download panel updater: %w\", reqErr)\n\t}\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"download panel updater: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn \"\", fmt.Errorf(\"download panel updater: unexpected HTTP %d\", resp.StatusCode)\n\t}\n\n\tfile, err := os.CreateTemp(\"\", \"3x-ui-update-*.sh\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tpath := file.Name()\n\tok := false\n\tdefer func() {\n\t\t_ = file.Close()\n\t\tif !ok {\n\t\t\t_ = os.Remove(path)\n\t\t}\n\t}()\n\n\tn, err := io.Copy(file, io.LimitReader(resp.Body, maxPanelUpdaterBytes+1))\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"write panel updater: %w\", err)","sourceCodeStart":351,"sourceCodeEnd":387,"githubUrl":"https://github.com/MHSanaei/3x-ui/blob/ad32144c42455696ea9f14e12168beac3e25f5d2/internal/web/service/panel/panel.go#L351-L387","documentation":"The updater script URL answered, but with a non-200 status — the download is refused at the HTTP layer. Typical codes: 404 (script moved / wrong release tag, e.g. a dev channel request against a tag that has no asset), 403 (rate-limited or blocked by the host/CDN), 5xx. The response body is discarded; only the code is reported.","triggerScenarios":"Panel update triggered when the upstream host returns 404/403/5xx for panelUpdaterURL — e.g. the script was relocated, the release asset is missing for the requested channel, or CDN rate limiting kicked in.","commonSituations":"GitHub rate limiting an automated/frequent update check; upstream repo reorganization that moved the script; requesting the dev channel before its release assets exist.","solutions":["Reproduce the exact code: curl -sI <updater-url> from the server","404 -> the URL/tag is stale; update the panel via the official install script or wait for an upstream fix","403/429 -> rate-limited; wait and retry, or route through the configured proxy","5xx -> upstream outage; retry later"],"exampleFix":"curl -sI https://raw.githubusercontent.com/MHSanaei/3x-ui/master/install.sh\n# HTTP 404 -> channel tag wrong; use the stable channel or update manually:\n# bash <(curl -fsSL https://raw.githubusercontent.com/MHSanaei/3x-ui/master/install.sh)","handlingStrategy":"retry","validationCode":"resp, err := http.Head(panelUpdaterURL) // through same proxy\nif err == nil && resp.StatusCode != http.StatusOK {\n    return fmt.Errorf(\"updater host returned %d; defer update\", resp.StatusCode)\n}","typeGuard":null,"tryCatchPattern":"_, err := panelService.StartUpdate(false)\nif err != nil && strings.Contains(err.Error(), \"unexpected HTTP\") {\n    // 404 = stale asset, stop; 403/429/5xx = rate limit/outage, retry with backoff\n}","preventionTips":["Avoid hammering update checks (rate limits on the script host)","Fall back to the official manual install script when the hosted asset 404s"],"tags":["http-status","updates","download","external-dependency","panel-update"],"backgroundTag":null,"analyzedSha":"ad32144c42455696ea9f14e12168beac3e25f5d2","analyzedAt":"2026-08-15T11:13:23.905Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}