Skip to content

Don't require --source when partial source failure leaves a single result#6165

Open
Sinan-Karakaya wants to merge 2 commits intomicrosoft:masterfrom
Sinan-Karakaya:master
Open

Don't require --source when partial source failure leaves a single result#6165
Sinan-Karakaya wants to merge 2 commits intomicrosoft:masterfrom
Sinan-Karakaya:master

Conversation

@Sinan-Karakaya
Copy link
Copy Markdown

@Sinan-Karakaya Sinan-Karakaya commented Apr 21, 2026

Fixes #6164

Right now, when one or more sources fail during an install search, winget shows the results from the sources that did respond and asks you to pick one via --source even if there's only one result. This happens in HandleSearchResultFailures via the ShowSearchResultsOnPartialFailure flag, which is set exclusively by the install command.

The fix is small: before routing into the "error and stop" path, check whether we're in install mode with exactly one match. If so, fall into the same "warn and continue" path that TreatSourceFailuresAsWarning already uses, the failed sources still get surfaced as warnings, but the install proceeds.

Existing behavior is preserved for:

  • Zero results from working sources -> still a hard error
  • Two or more results -> still shows the ambiguous list and requires --source
  • All other commands (search, upgrade, etc.) -> unaffected, they don't set ShowSearchResultsOnPartialFailure
Microsoft Reviewers: Open in CodeFlow

Treat source failures as warnings instead of errors when the install command finds
exactly one result from working sources, avoiding the need for the user to
manually specify --source.

Signed-off-by: Sinan Karakaya <me@sinankarakaya.fr>
Copilot AI review requested due to automatic review settings April 21, 2026 20:03
@Sinan-Karakaya Sinan-Karakaya requested a review from a team as a code owner April 21, 2026 20:03
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes winget install behavior when some configured sources fail during search: if exactly one package match is returned from the working sources, the install should proceed (while still surfacing failed sources as warnings) instead of stopping and requiring --source.

Changes:

  • In HandleSearchResultFailures, treat partial-source failures as warnings (not a hard error) when ShowSearchResultsOnPartialFailure is set and exactly one match exists.
  • Preserve existing hard-error behavior for zero matches or multiple matches under partial failure.

Comment thread src/AppInstallerCLICore/Workflows/WorkflowBase.cpp Outdated
Comment thread src/AppInstallerCLICore/Workflows/WorkflowBase.cpp Outdated
@denelon
Copy link
Copy Markdown
Collaborator

denelon commented Apr 21, 2026

I'm not sure that's the behavior we want.

Given multiple sources configured in WinGet and a "search sequence" if two sources would both return "one best match" the user should disambiguate, or source priority should "break the tie".

I'd be more in favor of an interactive prompt with the one best match and the source(s) with failures.

That also begs the question about what the default behavior should be when interactivity is disabled.

@denelon denelon marked this pull request as draft April 21, 2026 22:06
@JohnMcPMS
Copy link
Copy Markdown
Member

If there is an error searching one or more sources, we don't know if there is really only one result. That is why there is a hard error and the user must explicitly choose the target source.

Refactors `IsInteractivityAllowed` out of an anonymous namespace to allow broader usage. Updates the partial search failure logic to prompt the user if exactly one match is found and interactivity is allowed, rather than auto-proceeding or failing.

Signed-off-by: Sinan KARAKAYA<me@sinankarakaya.fr>
@Sinan-Karakaya
Copy link
Copy Markdown
Author

Thanks for the feedback, all fair points. I've reworked the approach based on the discussion:

Instead of silently auto-proceeding, the updated behavior now shows a [Y] Yes / [N] No prompt when ShowSearchResultsOnPartialFailure is set and exactly one match was found, so the user stays in control rather than having winget make the decision for them. The failures are still surfaced as warnings before the prompt, so the user knows what failed before deciding.

For the non-interactive case (COM callers, --disable-interactivity, the user setting), it falls straight through to the original hard error path. This way there are no prompt, no silent proceed, and it fails as expected.

On the "we don't know if there's really only one result" point: agreed, the prompt doesn't change that. But it shifts responsibility to the user: they're explicitly acknowledging they want to proceed despite the uncertainty, rather than winget guessing on their behalf. If they want certainty, they can still --source manually.

The comment was also updated to reference ShowSearchResultsOnPartialFailure directly instead of saying "install command", since that was both inaccurate and brittle. And I've added unit tests covering the three paths: interactive accept, interactive decline, and non-interactive (hard error).

The source priority / hunt sequence tie-breaking is a separate and more involved problem. I'd be happy to track that as a follow-up if that's useful, but I don't think it blocks this.

@Sinan-Karakaya
Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

@Trenly
Copy link
Copy Markdown
Contributor

Trenly commented Apr 22, 2026

Maybe we need to re-think the user settings for interactivity a bit @denelon ? I could see a case where a user would want to specify the default behavior for each interaction

For example, disable interactivity and don't accept any source agreements, but still proceed if there were source failures. Proceed through prompt for an install path with a user-defined default but hard stop on configuration review / continue prompt

Probably a bit outside the scope of this PR, but just something it brought to mind

@denelon
Copy link
Copy Markdown
Collaborator

denelon commented Apr 22, 2026

I created:

to address the tie-breaking scenario so this PR can be reviewed.

@denelon denelon marked this pull request as ready for review April 22, 2026 15:19
namespace AppInstaller::CLI::Workflow
{
namespace
bool IsInteractivityAllowed(Execution::Context& context)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't want this to be publicly visible; callers should be required to go through our explicitly defined prompt flows rather than making arbitrary choices about handling interactivity. That also makes the call sites less cluttered, as they are forced to simply invoke a prompt function with a default rather than have control flow.

I think that the correct approach is going to be refactoring the Reporter prompt methods out into PromptFlow.cpp and have them invoke this function in addition to other checks they do to determine whether to actually prompt or not.

// When ShowSearchResultsOnPartialFailure is set (e.g. install) and exactly one match
// was found, prompt the user interactively rather than failing outright.
// Falls back to the hard error path if interactivity is disabled.
else if (WI_IsFlagSet(context.GetFlags(), Execution::ContextFlag::ShowSearchResultsOnPartialFailure) &&
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This block duplicates a lot of code from the other blocks. I would rather we just accept the error output and move the prompt invocation into the correct location in the existing else.

If a warning about each source is a critical change to you, the entire function could probably be refactored to better make sematic decisions up front and then execute on those using a more common code path:

  1. Are we using warnings or errors? Save that choice, select output stream and lambda body to match.
  2. Enumerate failures, invoke output lambda, extract HRESULT (even if warning).
  3. If we decided this is a warning, return.
  4. Continue on with the second half of the existing else with the new prompt.

</data>
<data name="SearchFailureSingleResultPrompt" xml:space="preserve">
<value>A package was found among the working sources. Would you like to proceed?</value>
<comment>"working sources" as in "sources that are working correctly"</comment>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
<comment>"working sources" as in "sources that are working correctly"</comment>
<comment>"working sources" as in "package sources that are functioning properly"</comment>


TEST_CASE("HandleSearchResultFailures_SingleMatchWithPartialFailure", "[HandleSearchResultFailures][workflow]")
{
auto makeSearchResult = []()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: catch2 runs the entire test multiple times, dynamically enabling sections each time to get the complete set. You can just build the result in a local in the test rather than using a lambda. Mostly saves a few lines of code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

winget install requires --source even when only one result exists from working sources

5 participants