{"record":{"id":"d1566641247d9d2f","repo":"Devolutions/UniGetUI","slug":"the-updater-download-server-returned-partial-conte","errorCode":null,"errorMessage":"The updater download server returned partial content with a changed validator.","messagePattern":"The updater download server returned partial content with a changed validator\\.","errorType":"exception","errorClass":"InvalidDataException","httpStatus":null,"severity":"error","filePath":"src/UniGetUI.Core.Tools/UpdaterDownloadEngine.cs","lineNumber":215,"sourceCode":"            }\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        {\n            if (!allowRestart)\n            {\n                throw new InvalidDataException(\n                    \"The updater download server returned partial content with a changed validator.\"\n                );\n            }\n\n            log?.Invoke(\"Updater download validator changed during resume; 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 && partialLength > 0)\n        {","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/Devolutions/UniGetUI/blob/9b1d7d0eab91620fc15c86b36676532095936ae3/src/UniGetUI.Core.Tools/UpdaterDownloadEngine.cs#L197-L233","documentation":"During a resume, if the server returns 206 Partial Content, IsResumeValidatorCompatible compares the stored metadata's ETag (or Last-Modified) against the response's current ETag/Last-Modified. If they differ the remote file changed mid-download. The engine deletes the partial and restarts when allowRestart is true. The InvalidDataException is thrown only on the recursive call (allowRestart=false), meaning the validator changed on both attempts — the asset is being mutated server-side between requests and a safe resume is impossible.","triggerScenarios":"A partial download was paused. On resume, the server returns 206 but with a different ETag or Last-Modified than recorded in the .part.json metadata, indicating the released artifact changed. The engine restarts, and on the fresh request the validator has changed yet again (e.g. a rolling deployment is actively replacing the asset), triggering the throw.","commonSituations":"The update server republished or overwrote the installer at the same URL with different content (new hash, new ETag). A CI/CD pipeline is mid-deploy and the asset is in flux. A mirror is serving a stale cached ETag that flips between two values. The release was yanked and replaced between the initial download and the resume.","solutions":["Delete the .part and .part.json files, then re-download from scratch — the stored partial belongs to a superseded artifact.","Confirm the download URL is stable (immutable release artifact) rather than a mutable 'latest' redirect target.","If the asset is genuinely being replaced, wait for the deployment to settle and retry the update check to obtain a fresh UpdaterDownloadIdentity.","Verify the mirror/CDN is not serving conflicting validators for the same URL."],"exampleFix":"// before: resume fails because the remote artifact changed\nUpdaterDownloadEngine.DownloadInstallerPartAsync(client, identity, destPath)\n// after: discard the stale partial tied to the old validator\nUpdaterDownloadEngine.DeletePartialDownload(destPath);\nawait UpdaterDownloadEngine.DownloadInstallerPartAsync(client, identity, destPath);","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await UpdaterDownloadEngine.DownloadInstallerPartAsync(client, identity, destPath); }\ncatch (InvalidDataException ex) when (ex.Message.Contains(\"changed validator\"))\n{ UpdaterDownloadEngine.DeletePartialDownload(destPath); /* the remote artifact changed; re-fetch identity */ }","preventionTips":["Point update URLs at immutable release artifacts, not mutable 'latest' links.","Re-fetch the UpdaterDownloadIdentity (version + hash) before resuming if the release was updated.","Discard .part files whose metadata predates a known release change."],"tags":["autoupdater","download","http","etag","resume","network"],"backgroundTag":null,"analyzedSha":"9b1d7d0eab91620fc15c86b36676532095936ae3","analyzedAt":"2026-08-13T12:19:18.278Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}