{"record":{"id":"9a1ecb8da78ff3e6","repo":"beeradmoore/dlss-swapper","slug":"could-not-download-file","errorCode":null,"errorMessage":"Could not download file.","messagePattern":"Could not download file\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/Data/DLLRecord.cs","lineNumber":295,"sourceCode":"        _cancellationTokenSource = new CancellationTokenSource();\n        var cancellationToken = _cancellationTokenSource.Token;\n\n        var fileDownloader = new FileDownloader(DownloadUrl);\n        var tempZipFile = Path.Combine(Storage.GetTemp(), $\"{fileDownloader.Guid.ToString(\"D\").ToUpper()}.zip\");\n\n        try\n        {\n            LocalRecord.FileDownloader = fileDownloader;\n            NotifyPropertyChanged(nameof(LocalRecord));\n\n\n            using (var fileStream = new FileStream(tempZipFile, FileMode.Create, FileAccess.ReadWrite, FileShare.None, FileDownloader.BufferSize, true))\n            {\n                var didDownload = await LocalRecord.FileDownloader.DownloadFileToStreamAsync(fileStream, cancellationToken).ConfigureAwait(false);\n\n                if (didDownload == false)\n                {\n                    throw new Exception(\"Could not download file.\");\n                }\n\n                if (ZipMD5Hash != fileStream.GetMD5Hash())\n                {\n                    throw new Exception(\"Downloaded file was invalid.\");\n                }\n\n                fileStream.Position = 0;\n\n                using (var zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Read, true))\n                {\n                    DLLManager.HandleExtractFromZip(zipArchive, this);\n                }\n            }\n\n            App.CurrentApp.RunOnUIThread(() =>\n            {\n                LocalRecord.IsDownloaded = true;","sourceCodeStart":277,"sourceCodeEnd":313,"githubUrl":"https://github.com/beeradmoore/dlss-swapper/blob/ab9b1e2d4bb04187c48fe58eeea06c2b0ea71fbb/src/Data/DLLRecord.cs#L277-L313","documentation":"DLLRecord.DownloadAsync throws this when FileDownloader.DownloadFileToStreamAsync completes but reports didDownload == false, i.e. the HTTP transfer did not succeed (non-success status, empty body, or the downloader's failure condition) yet no exception was raised by the downloader itself. The library refuses to continue to zip validation/extraction with a file it did not actually download.","triggerScenarios":"Calling DownloadAsync (directly or via update/install flows) when the remote zip URL returns a non-success status the downloader tolerates, a redirect to an error page it treats as no-content, or the network drops such that the downloader returns false instead of throwing.","commonSituations":"CDN returning 403/404 handled as 'false' by FileDownloader; expired or moved GitHub release asset URL; firewall/proxy blocking the download host; rate limiting on the download endpoint.","solutions":["Check the package URL in the manifest is still valid (open it in a browser/curl)","Retry the download after verifying network/proxy access","Update the app/manifest to pick up corrected asset URLs","Inspect FileDownloader behavior/status codes for why it returned false and surface the HTTP status"],"exampleFix":"// before\nvar didDownload = await LocalRecord.FileDownloader.DownloadFileToStreamAsync(fileStream, cancellationToken).ConfigureAwait(false);\nif (didDownload == false)\n{\n    throw new Exception(\"Could not download file.\");\n}\n// after\nvar didDownload = await LocalRecord.FileDownloader.DownloadFileToStreamAsync(fileStream, cancellationToken).ConfigureAwait(false);\nif (didDownload == false)\n{\n    throw new Exception($\"Could not download file from {DownloadUrl}.\");\n}","handlingStrategy":"retry","validationCode":"// preflight the URL before DownloadAsync\nusing var resp = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, downloadUrl));\nif (!resp.IsSuccessStatusCode)\n    throw new HttpRequestException($\"Asset URL {downloadUrl} returned {(int)resp.StatusCode}.\");","typeGuard":null,"tryCatchPattern":"try\n{\n    await dllRecord.DownloadAsync();\n}\ncatch (Exception ex) when (ex.Message == \"Could not download file.\")\n{\n    await Task.Delay(TimeSpan.FromSeconds(5));\n    await dllRecord.DownloadAsync(); // one retry before surfacing to user\n}","preventionTips":["Verify asset URLs with a HEAD request when the manifest updates","Implement bounded retries with exponential backoff","Show the failing URL in user-facing error output","Watch for CDN/GitHub rate limits and 403s in logs"],"tags":["network","download","http","dotnet"],"backgroundTag":"http-request-failed","analyzedSha":"ab9b1e2d4bb04187c48fe58eeea06c2b0ea71fbb","analyzedAt":"2026-09-15T05:25:32.979Z","contentChangedAt":"2026-09-15T05:25:32.979Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}