Devolutions/UniGetUI · error · FileNotFoundException
The completed updater partial file was not found.
Error message
The completed updater partial file was not found.
What it means
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.
Source
Thrown at src/UniGetUI.Core.Tools/UpdaterDownloadEngine.cs:278
newMetadata.TotalLength ??= bytesInPartial;
newMetadata.UpdatedUtc = DateTime.UtcNow;
WriteMetadata(metadataPath, newMetadata, log);
return new UpdaterDownloadResult(
partialPath,
bytesInPartial,
newMetadata.TotalLength,
response.StatusCode,
Resumed: appendToPartial
);
}
public static void PromotePartialDownload(string destinationPath, Action<string>? log = null)
{
string partialPath = GetPartialPath(destinationPath);
if (!File.Exists(partialPath))
{
throw new FileNotFoundException("The completed updater partial file was not found.", partialPath);
}
File.Move(partialPath, destinationPath, overwrite: true);
DeleteFileIfExists(GetPartialMetadataPath(destinationPath), log);
}
public static void DeletePartialDownload(string destinationPath, Action<string>? log = null)
{
DeleteFileIfExists(GetPartialPath(destinationPath), log);
DeleteFileIfExists(GetPartialMetadataPath(destinationPath), log);
}
public static bool IsFailureBackoffActive(
string statePath,
UpdaterDownloadIdentity identity,
DateTime utcNow,
out TimeSpan remaining,
out UpdaterDownloadFailureState? state,View on GitHub (pinned to 9b1d7d0eab)
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.
Example fix
// before: promote called without confirming the partial exists
UpdaterDownloadEngine.PromotePartialDownload(destPath);
// after: guard the promotion
string partial = UpdaterDownloadEngine.GetPartialPath(destPath);
if (File.Exists(partial))
UpdaterDownloadEngine.PromotePartialDownload(destPath);
else
await UpdaterDownloadEngine.DownloadInstallerPartAsync(client, identity, destPath); Defensive patterns
Strategy: validation
Validate before calling
string partial = UpdaterDownloadEngine.GetPartialPath(destPath);
if (!File.Exists(partial))
throw new InvalidOperationException($"Cannot promote: partial file missing at {partial}"); Type guard
static bool CanPromotePartial(string destPath) => File.Exists(UpdaterDownloadEngine.GetPartialPath(destPath));
Try / catch
try { UpdaterDownloadEngine.PromotePartialDownload(destPath); }
catch (FileNotFoundException ex) { Logger.Error(ex); /* re-download before promoting */ } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- The updater download server returned an invalid partial cont
- The updater download server returned partial content with a
- No compatible installer file found in productinfo for archit
AI-assisted analysis of Devolutions/UniGetUI@9b1d7d0eab (2026-08-13).
Data as JSON: /api/errors/665116a135e9eb55.
Report an issue: GitHub.