{"record":{"id":"84a81ab917a54860","repo":"henrygd/beszel","slug":"d-failed-to-send-download-file-request","errorCode":null,"errorMessage":"(%d) failed to send download file request","messagePattern":"\\((.+?)\\) failed to send download file request","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/ghupdate/ghupdate.go","lineNumber":298,"sourceCode":"\tuseMirror bool,\n) error {\n\tif useMirror {\n\t\turl = strings.Replace(url, \"github.com\", \"gh.beszel.dev\", 1)\n\t}\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", url, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tres, err := client.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer res.Body.Close()\n\n\t// http.Client doesn't treat non 2xx responses as error\n\tif res.StatusCode >= 400 {\n\t\treturn fmt.Errorf(\"(%d) failed to send download file request\", res.StatusCode)\n\t}\n\n\t// ensure that the dest parent dir(s) exist\n\tif err := os.MkdirAll(filepath.Dir(destPath), os.ModePerm); err != nil {\n\t\treturn err\n\t}\n\n\tdest, err := os.Create(destPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer dest.Close()\n\n\tif _, err := io.Copy(dest, res.Body); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/henrygd/beszel/blob/b38fb7dafa60812cc22e6a84ce313e94f1ce0a32/internal/ghupdate/ghupdate.go#L280-L316","documentation":"downloadFile streams the release asset to a destination path. Because http.Client doesn't treat non-2xx responses as errors, the library checks the status itself and returns this error (with the status code) when the asset download request fails with >= 400. Unlike the releases-list error, the response body is not included, only the status code.","triggerScenarios":"Calling update (which calls downloadFile) when the asset URL responds 4xx/5xx — typically 404 because the release has no matching asset for the current OS/arch, 403 rate limiting, or an expired/removed release asset URL.","commonSituations":"New release published without an asset for your platform (wrong asset naming pattern); asset deleted or release re-tagged after publishing; GitHub API rate limit on repeated update checks; private repo asset requiring authentication.","solutions":["Check the status code in the error: 404 means the expected asset name doesn't exist — verify the release on GitHub has an asset matching your OS/arch naming.","Fix or extend the asset-name matching so the correct artifact is selected for your platform.","Authenticate requests to avoid 403 rate limits, and wait out the limit if already hit.","Retry later if the release was just published (assets may still be propagating)."],"exampleFix":"// before: release tagged v2.0 lacks a linux-arm64 asset\n$ ./myapp update\n// (404) failed to send download file request\n\n// after: pin/verify the release contains your platform's asset, or skip\n$ gh release view v2.0 --json assets   # confirm asset exists, then retry update","handlingStrategy":"retry","validationCode":"// verify the release has an asset for this platform before downloading\nGOOS := runtime.GOOS; GOARCH := runtime.GOARCH\nfor _, a := range rel.Assets {\n    if strings.Contains(a.GetName(), GOOS) && strings.Contains(a.GetName(), GOARCH) {\n        found = true\n    }\n}\nif !found { return fmt.Errorf(\"no asset for %s/%s in %s\", GOOS, GOARCH, rel.GetTagName()) }","typeGuard":"func isNotFoundErr(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"(404)\")\n}","tryCatchPattern":"if err := updater.Update(ctx, rel); err != nil {\n    if strings.Contains(err.Error(), \"failed to send download file request\") {\n        if strings.Contains(err.Error(), \"(403)\") { waitForRateLimitReset(); return retry() }\n        if strings.Contains(err.Error(), \"(404)\") { return fmt.Errorf(\"asset missing for this platform: %w\", err) }\n        return retry()\n    }\n    return err\n}","preventionTips":["Confirm each release publishes assets for all supported OS/arch pairs (CI release job).","Handle 403 rate limits with token auth and backoff.","Don't re-tag releases; published asset URLs must remain stable.","Skip update gracefully (log + continue) when the platform asset is absent."],"tags":["network","http","download","github-api"],"backgroundTag":"http-non-2xx-response","analyzedSha":"b38fb7dafa60812cc22e6a84ce313e94f1ce0a32","analyzedAt":"2026-08-31T15:10:10.149Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}