Skip to content

Drop scope and architecture when retrying WinGet with the local identifier - #5579

Merged
Gabriel Dufresne (GabrielDuf) merged 1 commit into
mainfrom
fix/issue-5522
Oct 22, 2026
Merged

Gabriel Dufresne (GabrielDuf) merged 1 commit into
mainfrom
fix/issue-5522

Conversation

@GabrielDuf

@GabrielDuf Gabriel Dufresne (GabrielDuf) commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor
  • I have read the contributing guidelines, and I agree with the Code of Conduct.
  • Have you checked that there aren't other open pull requests for the same changes?
  • Have you tested that the committed code can be executed without errors?
  • Have you confirmed that this issue is caused by UniGetUI itself, and not by the package manager or the package involved?
    If the same issue can be reproduced outside UniGetUI with the relevant package manager or with the package itself, please report it there first. UniGetUI should only be used to track issues that are specific to UniGetUI's behavior or integration.

Root cause

When WinGet returns 0x8A150014 ("No installed package found matching input criteria") for an update or uninstall, the #5413 fallback in WinGetPkgOperationHelper._getOperationResult sets OverridenOptions.WinGet_UseLocalIdentifier and returns AutoRetry. On the retry, GetSelectorPiece swaps the catalog id for the installed entry's local identifier (CatalogPackage.InstalledVersion.Id, for example ARP\Machine\X86\{141A88F8-...}_is1).

_getOperationParameters still added --scope (from GetEffectiveScope) and --architecture (from GetEffectiveArchitecture), both taken from the user's or package's install options. Neither getter honoured the local-identifier mode; they only checked WinGet_DropArchAndScope.

WinGet applies --scope as a filter on the installed-package query. On a real machine-scoped ARP entry:

  • winget list --id "ARP\Machine\X86\{58976FF3-...}" --exact finds the entry
  • the same with --scope machine finds it
  • the same with --scope user prints "No installed package found matching input criteria."

So for the reporter's machine-wide x86 FanControl install with a user-scope/x64 default, the retry was filtered out exactly like the first attempt. It failed with 0x8A150014 again, and since the flag was already set there was no further retry, so the update could never succeed. The "manual update" button goes through GetStandaloneParameters, which uses the same _getOperationParameters, so it printed the same broken command the commenter quoted.

Fix

In src/UniGetUI.PackageEngine.Managers.WinGet/Helpers/WinGetPkgOperationHelper.cs:

  • The "local identifier is actually in use" check moved into GetSelectedLocalIdentifier: WinGet_UseLocalIdentifier is set and GetFallbackIdentifier returns a usable id. GetSelectorPiece now uses it.
  • New DropsArchAndScope: WinGet_DropArchAndScope is set, or a local identifier is being selected.
  • GetEffectiveScope and GetEffectiveArchitecture return null whenever DropsArchAndScope is true, so no --scope or --architecture is emitted while a local identifier is in use.

Why this shape: the local identifier already names one exact installed entry, and its ARP path encodes that entry's own scope and architecture, so any scope or architecture constraint can only filter it out or disagree with it. Without the flags, winget keeps the installed scope and architecture on upgrade, which matches the CLI's default. The drop is tied to the selector actually using the local id, not to the flag alone, so the two cannot diverge: if the local id cannot be resolved, the normal id is used and the user's constraints are kept. Because the fix sits inside the two existing getters, both the operation path (GetParameters) and the manual-update/terminal path (GetStandaloneParameters) are covered. The 0x8A15002B "not applicable" retry check also correctly sees nothing left to drop.

Verification

  • Build: dotnet build src/UniGetUI.PackageEngine.Managers.WinGet/UniGetUI.PackageEngine.Managers.WinGet.csproj -p:Platform=x64 -p:UseSharedCompilation=false: exit 0, 0 errors. The test project also built as part of dotnet test.
  • Whitespace formatter: dotnet format whitespace src --folder --verify-no-changes: exit 0.
  • Style formatter, scoped to the changed projects: dotnet format style src/UniGetUI.Windows.slnx --no-restore --verify-no-changes --include src/UniGetUI.PackageEngine.Managers.WinGet/ src/UniGetUI.PackageEngine.Tests/: exit 0.
  • Style formatter, whole solution: exit 2, with every hit being IDE0044/IDE0060 in UniGetUI.Avalonia and UniGetUI.Tui files this change does not touch ([ObservableProperty] fields and XAML event handlers). These are the usual false positives when source generators have not run in a fresh, unbuilt worktree with --no-restore; CI builds first.
  • Tests (filtered, results read from TRX): the new test fails without the fix (Assert.DoesNotContain() Failure on --scope in the retry parameters, checked by stashing only WinGetPkgOperationHelper.cs) and passes with it. Together with the neighbouring local-identifier tests (WinGetUpdateRetriesWithTheLocalIdentifierWhenNoInstalledPackageMatches, WinGetUninstallRetriesWithTheLocalIdentifierWhenNoInstalledPackageMatches, WinGetUpdateUsesTheLocalIdentifierFromTheLatestListing): 4 run, 4 passed.
  • Not run locally: the full suite is left to CI.
  • Ground truth: winget list --scope against a real machine-scoped ARP entry, as described under Root cause.

Regression test

UniGetUI.PackageEngine.Tests.WinGetManagerTests.WinGetLocalIdentifierRetryDropsTheScopeAndArchitectureThatHidTheInstalledEntry: fails without the fix, passes with it.

Not covered

  • First attempt unchanged: the first attempt with the catalog id (e.g. Rem0o.FanControl) still sends the user's --scope/--architecture. Those are user choices and are what make the catalog-id selection meaningful; they are only relaxed once the retry has pinned the exact installed entry.
  • No scope/arch retry without a local id: if 0x8A150014 is caused purely by a scope mismatch and no local identifier can be resolved (COM unavailable), there is still no retry that drops scope/architecture. Adding one would widen the [BUG] UniGet targets the incorrect update id/name in winget #5413 fallback beyond this report.
  • Agent broker path: BrokerRequestBuilder is unchanged. The local-identifier retry is already disabled for brokered operations (OperationIsBrokered), so the broker never sees this flag.
  • Not verified end to end: no real winget upgrade of an outdated, machine-scoped, ARP-correlated package was run. The filtering behaviour was confirmed with winget list --scope, which uses the same installed-package query.

Review notes (non-blocking)

  • Not verified end to end. The claim that winget keeps the installed architecture when no --architecture is given on upgrade comes from the CLI's documented default, not from an experiment.
  • Side effect in PingetPackageDetailsProvider.GetConfiguredInstallerPreference (ClientHelpers/PingetPackageDetailsProvider.cs:542): it calls GetEffectiveScope/GetEffectiveArchitecture, so while WinGet_UseLocalIdentifier is set on a package and its local id resolves, the installer preference becomes (null, null). This only happens after a 0x8A150014 retry and matches what WinGet_DropArchAndScope already does, so it is consistent rather than a regression.
  • Behaviour change on the 0x8A15002B path (WinGetPkgOperationHelper.cs:374-385): after a local-identifier retry, scope and architecture already resolve to null, so an "update not applicable" result no longer triggers a second relaxed retry and goes straight to SuppressPhantomUpgrade and Failure. That is right, since nothing is left to drop, but no test covers this new path.
  • The case where 0x8A150014 is caused only by scope and no local identifier can be resolved (e.g. COM unavailable) is not covered; it is out of scope for Uniget Will Not Update Some Packages Installed Via Winget #5522.

Refs #5522 - this fixes the local-identifier retry failure EotT123 reported in that thread (ARP\Machine\X86\... id combined with --scope user --architecture x64). The original Vivaldi report could not be diagnosed (no logs or error code), so this PR does not close the issue.

🤖 Generated with Claude Code

…ifier

When WinGet answers an update or uninstall with 0x8A150014 ("No installed
package found matching input criteria"), the #5413 fallback retries with
the installed entry's local identifier (for example an ARP\Machine\X86\
{...}_is1 key). The retry still passed --scope and --architecture from the
user's or package's install options, and WinGet applies --scope as a filter
on the installed-package query: `winget list --id <ARP id> --exact --scope
user` reports no match for a machine-wide entry. So a machine-wide x86
install with a user-scope/x64 default was filtered out again, failed with
the same error, and since the flag was already set it never retried. The
manual-update command shared the same parameters and printed the same
broken command line.

The local identifier already names one exact installed entry, and its ARP
path encodes that entry's own scope and architecture, so any constraint
can only hide it or disagree with it. GetEffectiveScope and
GetEffectiveArchitecture now return null whenever the selector actually
uses a resolved local identifier, which is tied to the same check
GetSelectorPiece uses so the two cannot diverge. If the local id cannot be
resolved the catalog id is used and the user's constraints are kept. The
first attempt with the catalog id is unchanged.

Fixes #5522

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The focused change preserves normal selector behavior and covers both command-generation paths, with no blocking issues identified.

No open issues 🎉

What changed in this PR

Fixes WinGet retries that still fail because scope or architecture constraints conflict with the selected local installed-package identifier, addressing the reported update failure in #5522.

Changes:

  • Centralizes local-identifier selection and omits scope and architecture only when a usable local identifier is selected or the existing drop flag is set.
  • Adds regression coverage confirming that initial constraints remain intact and are omitted from both retry and standalone commands.
File Description
src/​UniGetUI.PackageEngine.Tests/​WinGetManagerTests.cs Adds regression coverage for constrained updates retried with a local identifier.
src/​UniGetUI.PackageEngine.Managers.WinGet/​Helpers/​WinGetPkgOperationHelper.cs Aligns scope and architecture filtering with local-identifier selection.

Review effort: Balanced

@randy-but-a-ro randy-but-a-ro Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Pull request was approved automatically: the AI review is complete and all its review threads are resolved. 🎉

Integration Details
{
	"deliveryId": "5700eab0-ce41-11f1-9560-f6c4eaaa1833",
	"headSha": "60fef0fdbe1ad908a4f5432d4a3ee6dc4d7ab186",
	"reviewer": "copilot-pull-request-reviewer[bot]"
}

@GabrielDuf
Gabriel Dufresne (GabrielDuf) merged commit 2f1659f into main Oct 22, 2026
6 checks passed
@GabrielDuf
Gabriel Dufresne (GabrielDuf) deleted the fix/issue-5522 branch October 22, 2026 19:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants