{"record":{"id":"9b0cf550bdb4ebe7","repo":"JosefNemec/Playnite","slug":"failed-to-download-installer-manifest","errorCode":null,"errorMessage":"Failed to download installer manifest.","messagePattern":"Failed to download installer manifest\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"critical","filePath":"source/Tools/PlayniteInstaller/MainViewModel.cs","lineNumber":258,"sourceCode":"                webClient = null;\r\n            }\r\n        }\r\n\r\n        private async Task<List<string>> TryDownloadManifest(List<string> urls)\r\n        {\r\n            foreach (var url in urls)\r\n            {\r\n                try\r\n                {\r\n                    return ParseList(await webClient.DownloadStringTaskAsync(url));\r\n                }\r\n                catch (Exception e)\r\n                {\r\n                    logger.Error(e, $\"Failed to download installer manifest from {url}\");\r\n                }\r\n            }\r\n\r\n            throw new Exception(\"Failed to download installer manifest.\");\r\n        }\r\n\r\n        private async Task<bool> TryDownloadInstaller(List<string> urls)\r\n        {\r\n            foreach (var url in urls)\r\n            {\r\n                try\r\n                {\r\n                    await webClient.DownloadFileTaskAsync(url, App.InstallerDownloadPath);\r\n                    return true;\r\n                }\r\n                catch (WebException webExp)\r\n                {\r\n                    if (webExp.Status == WebExceptionStatus.RequestCanceled)\r\n                    {\r\n                        return false;\r\n                    }\r\n                    else\r","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/JosefNemec/Playnite/blob/5911f4e964e628aa7a69c2030ab35101afa63067/source/Tools/PlayniteInstaller/MainViewModel.cs#L240-L276","documentation":"Thrown by MainViewModel.GetInstallerManifest after every URL in the candidate list fails. The loop tries DownloadStringTaskAsync per URL, logs each per-URL failure, and only throws the generic message when none succeed. So the real cause (DNS, 404, TLS, proxy, offline) is in the preceding logger.Error entries — this throw is the aggregate failure.","triggerScenarios":"All installer-manifest URLs are unreachable: no network, corporate proxy blocking the hosts, the manifest moved (404), TLS handshake failure against the server, or the server is down. The exception message itself carries no detail by design.","commonSituations":"Offline machine; firewall/proxy blocking the Playnite update domain; the manifest hosting URL changed between releases; transient ISP outage; captive portal intercepting the request.","solutions":["Inspect the preceding log lines — each per-URL 'Failed to download installer manifest from <url>' carries the actual WebException/inner exception.","Verify network connectivity and DNS resolution for each URL in the list; test with a browser or `curl`.","Configure/whitelist the proxy and required hosts, then retry the installer manifest fetch.","If a specific URL is permanently 404, update the manifest URL list to the current Playnite distribution endpoint."],"exampleFix":"// before\nforeach (var url in urls)\n{\n    try { return ParseList(await webClient.DownloadStringTaskAsync(url)); }\n    catch (Exception e) { logger.Error(e, $\"Failed to download installer manifest from {url}\"); }\n}\nthrow new Exception(\"Failed to download installer manifest.\");\n\n// after (surface aggregated detail for diagnosis)\nvar errors = new List<Exception>();\nforeach (var url in urls)\n{\n    try { return ParseList(await webClient.DownloadStringTaskAsync(url)); }\n    catch (Exception e) { logger.Error(e, $\"Failed to download installer manifest from {url}\"); errors.Add(e); }\n}\nthrow new AggregateException(\"Failed to download installer manifest from any URL.\", errors);","handlingStrategy":"retry","validationCode":"if (urls == null || urls.Count == 0)\n    throw new InvalidOperationException(\"No installer manifest URLs configured.\");","typeGuard":null,"tryCatchPattern":"Exception lastError = null;\nforeach (var url in urls)\n{\n    try { return ParseList(await webClient.DownloadStringTaskAsync(url)); }\n    catch (Exception e) { logger.Error(e, $\"manifest fetch failed: {url}\"); lastError = e; }\n}\nthrow new Exception(\"Failed to download installer manifest.\", lastError); // preserve inner cause","preventionTips":["Always surface the inner per-URL exception (AggregateException or innerException) so users see *why* it failed.","Keep the manifest URL list current with the live distribution endpoint.","Provide a proxy configuration path and validate DNS/TLS reachability before the installer run."],"tags":["installer","network","download","manifest","retry-exhausted"],"backgroundTag":null,"analyzedSha":"5911f4e964e628aa7a69c2030ab35101afa63067","analyzedAt":"2026-08-13T17:38:25.713Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}