MHSanaei/3x-ui · error

download panel updater: unexpected HTTP %d

Error message

download panel updater: unexpected HTTP %d

What it means

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.

Source

Thrown at internal/web/service/panel/panel.go:369

func releaseUpdateSlot() {
	updateMu.Lock()
	updateRunning = false
	updateMu.Unlock()
}

func downloadPanelUpdater() (string, error) {
	client := (&service.SettingService{}).NewProxiedHTTPClient(15 * time.Second)
	req, reqErr := http.NewRequestWithContext(context.Background(), http.MethodGet, panelUpdaterURL, nil)
	if reqErr != nil {
		return "", fmt.Errorf("download panel updater: %w", reqErr)
	}
	resp, err := client.Do(req)
	if err != nil {
		return "", fmt.Errorf("download panel updater: %w", err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("download panel updater: unexpected HTTP %d", resp.StatusCode)
	}

	file, err := os.CreateTemp("", "3x-ui-update-*.sh")
	if err != nil {
		return "", err
	}
	path := file.Name()
	ok := false
	defer func() {
		_ = file.Close()
		if !ok {
			_ = os.Remove(path)
		}
	}()

	n, err := io.Copy(file, io.LimitReader(resp.Body, maxPanelUpdaterBytes+1))
	if err != nil {
		return "", fmt.Errorf("write panel updater: %w", err)

View on GitHub (pinned to ad32144c42)

Solutions

  1. Reproduce the exact code: curl -sI <updater-url> from the server
  2. 404 -> the URL/tag is stale; update the panel via the official install script or wait for an upstream fix
  3. 403/429 -> rate-limited; wait and retry, or route through the configured proxy
  4. 5xx -> upstream outage; retry later

Example fix

curl -sI https://raw.githubusercontent.com/MHSanaei/3x-ui/master/install.sh
# HTTP 404 -> channel tag wrong; use the stable channel or update manually:
# bash <(curl -fsSL https://raw.githubusercontent.com/MHSanaei/3x-ui/master/install.sh)
Defensive patterns

Strategy: retry

Validate before calling

resp, err := http.Head(panelUpdaterURL) // through same proxy
if err == nil && resp.StatusCode != http.StatusOK {
    return fmt.Errorf("updater host returned %d; defer update", resp.StatusCode)
}

Try / catch

_, err := panelService.StartUpdate(false)
if err != nil && strings.Contains(err.Error(), "unexpected HTTP") {
    // 404 = stale asset, stop; 403/429/5xx = rate limit/outage, retry with backoff
}

Prevention

When it happens

Trigger: 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.

Common situations: GitHub rate limiting an automated/frequent update check; upstream repo reorganization that moved the script; requesting the dev channel before its release assets exist.

Related errors


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