{"record":{"id":"1ee09836eed176e4","repo":"MHSanaei/3x-ui","slug":"panel-updater-download-is-empty","errorCode":null,"errorMessage":"panel updater download is empty","messagePattern":"panel updater download is empty","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/web/service/panel/panel.go","lineNumber":390,"sourceCode":"\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)\n\t}\n\tif n == 0 {\n\t\treturn \"\", fmt.Errorf(\"panel updater download is empty\")\n\t}\n\tif n > maxPanelUpdaterBytes {\n\t\treturn \"\", fmt.Errorf(\"panel updater exceeds %d bytes\", maxPanelUpdaterBytes)\n\t}\n\tif err := file.Chmod(0o700); err != nil {\n\t\treturn \"\", err\n\t}\n\tok = true\n\treturn path, nil\n}\n\nfunc fetchLatestPanelVersion() (string, error) {\n\trelease, err := fetchPanelRelease(\"\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif release.TagName == \"\" {\n\t\treturn \"\", fmt.Errorf(\"latest panel release tag is empty\")","sourceCodeStart":372,"sourceCodeEnd":408,"githubUrl":"https://github.com/MHSanaei/3x-ui/blob/ad32144c42455696ea9f14e12168beac3e25f5d2/internal/web/service/panel/panel.go#L372-L408","documentation":"Returned when the panel updater download completes (io.Copy succeeded) but exactly 0 bytes were written. The server returned HTTP 200 yet sent an empty body, which means the asset URL resolved to an empty file or an intermediary returned an empty 200. It is a data-integrity guard so an empty file is never chmod'd and executed.","triggerScenarios":"The updater asset URL responds 200 with Content-Length 0 or a body that closes immediately; a misconfigured reverse proxy or captive portal answering 200 with an empty page; the release asset being uploaded empty.","commonSituations":"Transparent corporate/NAT proxies that return empty 200s for unknown binaries; a GitHub release where the updater asset failed to upload; redirect chains that end in an empty response.","solutions":["curl -sIL the updater asset URL from the same host and confirm a non-zero Content-Length","Disable or bypass the HTTP proxy configured for outbound updates and retry","If the release asset itself is empty, wait for a fixed upstream release or download manually"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Head the asset before downloading the body\nresp, err := client.Head(assetURL)\nif err == nil && resp.ContentLength == 0 {\n    return errors.New(\"updater asset is empty upstream; refusing download\")\n}\n","typeGuard":null,"tryCatchPattern":"if _, err := panel.DownloadPanelUpdater(); err != nil {\n    if strings.Contains(err.Error(), \"download is empty\") {\n        // retry once, then report upstream asset problem\n    }\n}\n","preventionTips":["Treat any empty-body 200 from a download endpoint as interception until proven otherwise","Verify assets with a HEAD request before initiating update flows","Keep the panel's proxy settings accurate so empty proxy responses are not mistaken for upstream issues"],"tags":["download","updater","integrity"],"backgroundTag":null,"analyzedSha":"ad32144c42455696ea9f14e12168beac3e25f5d2","analyzedAt":"2026-08-15T11:13:23.905Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}