MHSanaei/3x-ui · error

panel updater exceeds %d bytes

Error message

panel updater exceeds %d bytes

What it means

Returned when the panel updater body streams more than maxPanelUpdaterBytes (2 MiB, io.LimitReader caps at +1 byte so an over-limit download is detected, not just truncated). Because the updater script is small, an oversized body almost always means the URL returned something other than the updater — typically an HTML error page or login page from a proxy. Prevents writing and executing an arbitrary oversized payload.

Source

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

	}
	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)
	}
	if n == 0 {
		return "", fmt.Errorf("panel updater download is empty")
	}
	if n > maxPanelUpdaterBytes {
		return "", fmt.Errorf("panel updater exceeds %d bytes", maxPanelUpdaterBytes)
	}
	if err := file.Chmod(0o700); err != nil {
		return "", err
	}
	ok = true
	return path, nil
}

func fetchLatestPanelVersion() (string, error) {
	release, err := fetchPanelRelease("")
	if err != nil {
		return "", err
	}
	if release.TagName == "" {
		return "", fmt.Errorf("latest panel release tag is empty")
	}
	return release.TagName, nil
}

View on GitHub (pinned to ad32144c42)

Solutions

  1. curl -sL the same URL and inspect Content-Type/size — HTML instead of the binary means proxy/captive-portal interception
  2. Fix or bypass the outbound proxy so the real asset is fetched
  3. If the genuine updater has grown past 2 MiB, bump maxPanelUpdaterBytes in internal/web/service/panel/panel.go and rebuild

Example fix

// before (panel.go:44)
maxPanelUpdaterBytes = 2 << 20
// after — only if the real asset outgrew the cap
maxPanelUpdaterBytes = 8 << 20
Defensive patterns

Strategy: validation

Validate before calling

resp, err := client.Head(assetURL)
if err == nil && resp.ContentLength > maxPanelUpdaterBytes {
    return fmt.Errorf("asset of %d bytes exceeds updater cap; check proxy interception", resp.ContentLength)
}

Prevention

When it happens

Trigger: The updater URL is intercepted by a captive portal / proxy auth page (HTML, hundreds of KB to MBs); the release asset was replaced by a large artifact; a redirect page served inline instead of followed.

Common situations: Egress through an authenticating HTTP proxy; CDN edge serving a big block page; pointing the updater at a wrong tag whose asset is a full binary, not the small updater script.

Related errors


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