{"record":{"id":"665116a135e9eb55","repo":"Devolutions/UniGetUI","slug":"the-completed-updater-partial-file-was-not-found","errorCode":null,"errorMessage":"The completed updater partial file was not found.","messagePattern":"The completed updater partial file was not found\\.","errorType":"exception","errorClass":"FileNotFoundException","httpStatus":null,"severity":"error","filePath":"src/UniGetUI.Core.Tools/UpdaterDownloadEngine.cs","lineNumber":278,"sourceCode":"        newMetadata.TotalLength ??= bytesInPartial;\n        newMetadata.UpdatedUtc = DateTime.UtcNow;\n        WriteMetadata(metadataPath, newMetadata, log);\n\n        return new UpdaterDownloadResult(\n            partialPath,\n            bytesInPartial,\n            newMetadata.TotalLength,\n            response.StatusCode,\n            Resumed: appendToPartial\n        );\n    }\n\n    public static void PromotePartialDownload(string destinationPath, Action<string>? log = null)\n    {\n        string partialPath = GetPartialPath(destinationPath);\n        if (!File.Exists(partialPath))\n        {\n            throw new FileNotFoundException(\"The completed updater partial file was not found.\", partialPath);\n        }\n\n        File.Move(partialPath, destinationPath, overwrite: true);\n        DeleteFileIfExists(GetPartialMetadataPath(destinationPath), log);\n    }\n\n    public static void DeletePartialDownload(string destinationPath, Action<string>? log = null)\n    {\n        DeleteFileIfExists(GetPartialPath(destinationPath), log);\n        DeleteFileIfExists(GetPartialMetadataPath(destinationPath), log);\n    }\n\n    public static bool IsFailureBackoffActive(\n        string statePath,\n        UpdaterDownloadIdentity identity,\n        DateTime utcNow,\n        out TimeSpan remaining,\n        out UpdaterDownloadFailureState? state,","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/Devolutions/UniGetUI/blob/9b1d7d0eab91620fc15c86b36676532095936ae3/src/UniGetUI.Core.Tools/UpdaterDownloadEngine.cs#L260-L296","documentation":"PromotePartialDownload moves the completed .part file to its final destination path via File.Move. Before moving, it checks File.Exists on the partial path. If the partial file is absent — deleted, moved by another process, never created, or the destinationPath was mangled so GetPartialPath resolves elsewhere — it throws FileNotFoundException with the partial path as the fileName argument. This is a hard precondition failure: the engine cannot promote a download that does not exist on disk.","triggerScenarios":"PromotePartialDownload is called but the corresponding .part file does not exist at GetPartialPath(destinationPath). This happens when DeletePartialDownload was already called (e.g. by a cleanup path or an error handler), when the download never ran, or when another process/thread removed the partial file between download completion and promotion.","commonSituations":"A race condition: one thread calls DeletePartialDownload while another calls PromotePartialDownload. An antivirus or cleanup utility quarantined the .part file. The destinationPath passed to PromotePartialDownload differs from the one passed to DownloadInstallerPartAsync (e.g. different working directory), so GetPartialPath resolves to a different location. The download was interrupted and PromotePartialDownload was invoked without a successful DownloadInstallerPartAsync call first.","solutions":["Verify the download completed successfully (UpdaterDownloadResult) before calling PromotePartialDownload.","Ensure the exact same destinationPath string is used for both DownloadInstallerPartAsync and PromotePartialDownload.","Check for concurrent cleanup paths or antivirus interference that removes .part files.","Call File.Exists on GetPartialPath(destinationPath) before promoting to give a clearer error or recover gracefully."],"exampleFix":"// before: promote called without confirming the partial exists\nUpdaterDownloadEngine.PromotePartialDownload(destPath);\n// after: guard the promotion\nstring partial = UpdaterDownloadEngine.GetPartialPath(destPath);\nif (File.Exists(partial))\n    UpdaterDownloadEngine.PromotePartialDownload(destPath);\nelse\n    await UpdaterDownloadEngine.DownloadInstallerPartAsync(client, identity, destPath);","handlingStrategy":"validation","validationCode":"string partial = UpdaterDownloadEngine.GetPartialPath(destPath);\nif (!File.Exists(partial))\n    throw new InvalidOperationException($\"Cannot promote: partial file missing at {partial}\");","typeGuard":"static bool CanPromotePartial(string destPath) => File.Exists(UpdaterDownloadEngine.GetPartialPath(destPath));","tryCatchPattern":"try { UpdaterDownloadEngine.PromotePartialDownload(destPath); }\ncatch (FileNotFoundException ex) { Logger.Error(ex); /* re-download before promoting */ }","preventionTips":["Always confirm DownloadInstallerPartAsync returned a complete result before calling PromotePartialDownload.","Use the same destinationPath for download and promote to avoid path mismatch.","Watch for antivirus or concurrent cleanup removing .part files."],"tags":["autoupdater","download","filesystem","partial-file"],"backgroundTag":null,"analyzedSha":"9b1d7d0eab91620fc15c86b36676532095936ae3","analyzedAt":"2026-08-13T12:19:18.278Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}