{"record":{"id":"c4f1ed949d77352c","repo":"Devolutions/UniGetUI","slug":"the-updater-download-server-returned-an-invalid-pa","errorCode":null,"errorMessage":"The updater download server returned an invalid partial content range.","messagePattern":"The updater download server returned an invalid partial content range\\.","errorType":"exception","errorClass":"InvalidDataException","httpStatus":null,"severity":"error","filePath":"src/UniGetUI.Core.Tools/UpdaterDownloadEngine.cs","lineNumber":194,"sourceCode":"            DeletePartialDownload(destinationPath, log);\n            return await DownloadInstallerPartAsync(\n                client,\n                identity,\n                destinationPath,\n                allowRestart: false,\n                log,\n                cancellationToken\n            );\n        }\n\n        response.EnsureSuccessStatusCode();\n\n        bool appendToPartial = response.StatusCode is HttpStatusCode.PartialContent;\n        if (appendToPartial && !IsValidPartialResponse(response, partialLength))\n        {\n            if (!allowRestart)\n            {\n                throw new InvalidDataException(\n                    \"The updater download server returned an invalid partial content range.\"\n                );\n            }\n\n            log?.Invoke(\"Updater download returned an invalid partial response; restarting.\");\n            DeletePartialDownload(destinationPath, log);\n            return await DownloadInstallerPartAsync(\n                client,\n                identity,\n                destinationPath,\n                allowRestart: false,\n                log,\n                cancellationToken\n            );\n        }\n\n        if (appendToPartial && !IsResumeValidatorCompatible(metadata, response))\n        {","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/Devolutions/UniGetUI/blob/9b1d7d0eab91620fc15c86b36676532095936ae3/src/UniGetUI.Core.Tools/UpdaterDownloadEngine.cs#L176-L212","documentation":"DownloadInstallerPartAsync requests a Range resume when a valid partial file and metadata exist. If the server responds with HTTP 206 Partial Content, IsValidPartialResponse checks that the Content-Range header's From value equals the current partialLength. When it does not, the engine normally deletes the partial and restarts (allowRestart=true). The InvalidDataException is only thrown on the recursive call where allowRestart is false — meaning the server returned a bad range twice in a row. This signals a genuinely broken CDN/mirror or a corrupted partial that cannot be trusted.","triggerScenarios":"A resume request (Range: bytes=N-) is sent. The server returns 206 but the Content-Range start byte differs from N. The engine deletes the partial, retries from byte 0 with allowRestart=false, and the server again returns 206 with a mismatched range start instead of a clean 200 or a correct 206. This requires a server that returns 206 status with inconsistent range data across two sequential requests.","commonSituations":"A reverse proxy or CDN rewrites Range responses incorrectly. The partial file was truncated externally and the metadata's recorded length drifted from the real file size. A load balancer routes the retry to a different backend that disagrees about the content range. The server does not support Range properly but advertises 206 anyway.","solutions":["Delete the .part file and its .part.json metadata manually, then retry the download from scratch.","Verify the download URL points to a server/CDN that correctly supports HTTP Range requests and returns accurate Content-Range headers.","Check that the partial file was not externally modified between the initial download and the resume attempt.","If behind a proxy, bypass it or reconfigure it to pass Range headers and Content-Range responses through unchanged."],"exampleFix":"// before: partial file present but range mismatch keeps failing\nUpdaterDownloadEngine.DownloadInstallerPartAsync(client, identity, destPath)\n// after: clean residual partial state then retry\nUpdaterDownloadEngine.DeletePartialDownload(destPath);\nawait UpdaterDownloadEngine.DownloadInstallerPartAsync(client, identity, destPath);","handlingStrategy":"retry","validationCode":"if (File.Exists(UpdaterDownloadEngine.GetPartialPath(destPath)))\n{\n    long partialLen = new FileInfo(UpdaterDownloadEngine.GetPartialPath(destPath)).Length;\n    if (partialLen == 0) UpdaterDownloadEngine.DeletePartialDownload(destPath);\n}","typeGuard":null,"tryCatchPattern":"try { await UpdaterDownloadEngine.DownloadInstallerPartAsync(client, identity, destPath); }\ncatch (InvalidDataException ex) when (ex.Message.Contains(\"invalid partial content range\"))\n{ UpdaterDownloadEngine.DeletePartialDownload(destPath); /* retry fresh */ }","preventionTips":["Download from CDNs that correctly implement HTTP Range and Content-Range.","Ensure no proxy rewrites Range responses.","Clean up .part and .part.json files before starting a fresh download session."],"tags":["autoupdater","download","http","resume","network"],"backgroundTag":null,"analyzedSha":"9b1d7d0eab91620fc15c86b36676532095936ae3","analyzedAt":"2026-08-13T12:19:18.278Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}