Devolutions/UniGetUI · error · KeyNotFoundException
No compatible installer file found in productinfo for archit
Error message
No compatible installer file found in productinfo for architecture '{targetArch}' What it means
SelectInstallerFile in AutoUpdaterHelpers picks an installer from the product-info files list. It searches in order: exe+targetArch, exe+Any, msi+targetArch, msi+Any. targetArch is derived from RuntimeInformation.ProcessArchitecture (arm64 -> "arm64", everything else -> "x64"). If none of the four combinations yield a match, a KeyNotFoundException is thrown. The match is case-insensitive ordinal on both Type and Arch.
Source
Thrown at src/Shared/AutoUpdater.Helpers.cs:69
match ??= files.FirstOrDefault(file =>
file.Type.Equals("exe", StringComparison.OrdinalIgnoreCase)
&& file.Arch.Equals("Any", StringComparison.OrdinalIgnoreCase)
);
match ??= files.FirstOrDefault(file =>
file.Type.Equals("msi", StringComparison.OrdinalIgnoreCase)
&& file.Arch.Equals(targetArch, StringComparison.OrdinalIgnoreCase)
);
match ??= files.FirstOrDefault(file =>
file.Type.Equals("msi", StringComparison.OrdinalIgnoreCase)
&& file.Arch.Equals("Any", StringComparison.OrdinalIgnoreCase)
);
if (match is null)
{
throw new KeyNotFoundException(
$"No compatible installer file found in productinfo for architecture '{targetArch}'"
);
}
return match;
}
internal static Version ParseVersionOrFallback(string rawVersion, Version fallbackVersion)
{
if (Version.TryParse(rawVersion, out Version? parsed))
{
return CoreTools.NormalizeVersionForComparison(parsed);
}
string sanitized = rawVersion.Trim().TrimStart('v', 'V');
if (Version.TryParse(sanitized, out parsed))
{
return CoreTools.NormalizeVersionForComparison(parsed);View on GitHub (pinned to 9b1d7d0eab)
Solutions
- Add an exe or msi ProductInfoFile entry to the product-info manifest whose Arch is the exact target architecture ("x64" or "arm64") or "Any".
- Verify the Arch strings use the canonical values "x64", "arm64", or "Any" — not "amd64", "aarch64", "x86_64".
- If the build target changed (e.g. new arm64 support), update every release manifest to include an installer for that architecture.
- Inspect the files list before calling SelectInstallerFile to confirm it is populated and that Type/Arch values are spelled correctly.
Example fix
// before: manifest only has a zip
files: [ { Type: "zip", Arch: "x64", Url: "..." } ]
// after: add an exe or msi with the canonical Arch
files: [
{ Type: "zip", Arch: "x64", Url: "..." },
{ Type: "exe", Arch: "x64", Url: "..." }
] Defensive patterns
Strategy: validation
Validate before calling
string targetArch = RuntimeInformation.ProcessArchitecture == Architecture.Arm64 ? "arm64" : "x64";
bool hasMatch = files.Any(f =>
(f.Type.Equals("exe", StringComparison.OrdinalIgnoreCase) || f.Type.Equals("msi", StringComparison.OrdinalIgnoreCase))
&& (f.Arch.Equals(targetArch, StringComparison.OrdinalIgnoreCase) || f.Arch.Equals("Any", StringComparison.OrdinalIgnoreCase)));
if (!hasMatch)
Logger.Warn($"No installer for architecture {targetArch}; available: {string.Join(", ", files.Select(f => $"{f.Type}/{f.Arch}"))}"); Type guard
static bool HasInstallerForArch(List<ProductInfoFile> files, string arch) =>
files.Any(f => (f.Type.Equals("exe", StringComparison.OrdinalIgnoreCase)
|| f.Type.Equals("msi", StringComparison.OrdinalIgnoreCase))
&& (f.Arch.Equals(arch, StringComparison.OrdinalIgnoreCase)
|| f.Arch.Equals("Any", StringComparison.OrdinalIgnoreCase))); Try / catch
try { var installer = AutoUpdaterHelpers.SelectInstallerFile(files); }
catch (KeyNotFoundException ex) { Logger.Error(ex); /* report missing installer to user */ } Prevention
- Always include an exe or msi entry with Arch="Any" as a fallback in release manifests.
- Use the canonical Arch strings "x64" and "arm64" — never "amd64" or "aarch64".
- Validate the manifest's files list in CI before publishing a release.
When it happens
Trigger: The product-info manifest's files array contains no ProductInfoFile whose Type is "exe" or "msi" AND whose Arch equals the running architecture or "Any". For example the manifest lists only "msix" or "zip" types, or only lists "arm64" while RuntimeInformation.ProcessArchitecture is X64 (or vice-versa). A typo such as Arch="x86_64" or Type="EXE " (trailing space) also produces no match because Equals is ordinal case-insensitive but does not trim.
Common situations: A release publishes only a zip/msix asset and omits exe/msi entries. A new architecture port (e.g. arm64) ships but the manifest was not updated with a matching installer row. The Arch column uses a different naming convention ("amd64" instead of "x64", "aarch64" instead of "arm64"). The manifest file is empty or the deserialized files list came back empty due to a schema change.
Related errors
- The updater download server returned an invalid partial cont
- The updater download server returned partial content with a
- The completed updater partial file was not found.
AI-assisted analysis of Devolutions/UniGetUI@9b1d7d0eab (2026-08-13).
Data as JSON: /api/errors/3b2826128d901c8c.
Report an issue: GitHub.