Skip to content

Fix misleading AppHost build failure diagnostics - #19082

Open
Ella Hathaway (ellahathaway) wants to merge 5 commits into
microsoft:mainfrom
ellahathaway:ellahathaway-fix-apphost-build-diagnostic
Open

Fix misleading AppHost build failure diagnostics#19082
Ella Hathaway (ellahathaway) wants to merge 5 commits into
microsoft:mainfrom
ellahathaway:ellahathaway-fix-apphost-build-diagnostic

Conversation

@ellahathaway

@ellahathaway Ella Hathaway (ellahathaway) commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Description

An AppHost can exist and still fail MSBuild evaluation — most commonly when Aspire.AppHost.Sdk cannot be resolved. ProjectLocator treated that signal (IsPossiblyUnbuildable) as "no such project", so the user was told the file did not exist, or that no AppHosts were found, and never saw the MSB4236 that explained the real problem.

This keeps the selection instead. An explicitly named file, an explicitly named directory holding a single candidate, and a configured aspire.config.json path are all deliberate user choices, so they are honored and the command's existing build path prints the diagnostics it already collects. That path needed no changes — it already stashes build output, reports FailedToBuildArtifacts, and displays the collected lines. The entire fix is contained in ProjectLocator.cs.

User-facing behavior

Before, for an AppHost whose SDK cannot be resolved:

--apphost ./MissingSdkAppHost/MissingSdkAppHost.csproj
  ❌ The --apphost option specified a project that does not exist.        (exit 7)

aspire.config.json -> ./MissingSdkAppHost/MissingSdkAppHost.csproj
  ❌ No AppHosts were found (there may be AppHost project files with
     syntax errors/invalid SDK versions).                                 (exit 7)

After, both paths reach the build and report what is actually wrong:

MissingSdkAppHost.csproj : error : Could not resolve SDK "Missing.AppHost.Sdk". Exactly one of the
probing messages below indicates why we could not resolve the SDK. Investigate and resolve that
message to correctly specify the SDK.
MissingSdkAppHost.csproj : error :   SDK resolver "Microsoft.DotNet.MSBuildWorkloadSdkResolver" returned null.
MissingSdkAppHost.csproj : error :   The NuGetSdkResolver did not resolve this SDK because there was
no version specified in the project or global.json.
MissingSdkAppHost.csproj : error MSB4236: The SDK 'Missing.AppHost.Sdk' specified could not be found.

Build FAILED.

❌ The project could not be built.                                        (exit 6)

What deliberately did not change

Ambient discovery. Finding only unbuildable candidates while scanning the working directory is still AppHostsMayNotBeBuildable mapped to FailedToFindProject. AppHostConnectionResolver.IsProjectResolutionError keys off that exit code to tell "AppHost not running" apart from "no project resolved"; remapping it makes stop/logs/describe/ps emit success-shaped output. AppHostConnectionResolverTests guards this.

Unsupported projects. IsUnsupported (for example a guest language unavailable in the current environment) still falls back to discovery. Only IsPossiblyUnbuildable is reinterpreted — the two were previously conflated in one theory, which is now split into two focused tests.

Ambiguous directories. An explicit directory containing more than one unbuildable candidate is a genuine ambiguity rather than a selection, so it still fails resolution. Candidates injected into the walk from a parent directory's config are excluded from that count, so --apphost ./some-dir never auto-selects a project that is not under ./some-dir.

Settings are never written from an unverified selection. A candidate kept only because MSBuild failed was never confirmed to be an AppHost; persisting it would let later ambient invocations silently reuse the guess.

Validation

  • ProjectLocatorTests — 98 tests (97 passed, 1 Windows-only skip), including 8 new regression tests covering the explicit-file, explicit-directory, configured, out-of-directory, and multiple-healthy-candidate paths.
  • RunCommandTests, UpdateCommandTests, AppHostConnectionResolverTests, AddCommandTests — 227/227.
  • End-to-end (RunReportsMissingSdkAsBuildFailureForDotNetAppHost) run in Docker against a locally built CLI. The asciinema recording confirms MSB4236 reaches the terminal, the shell reports exit code 6, and neither of the two misleading messages appears.

Fixes #19035

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0f00829a-32fc-44f6-bfb8-4310c86a460c
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0f00829a-32fc-44f6-bfb8-4310c86a460c
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0f00829a-32fc-44f6-bfb8-4310c86a460c
Copilot AI balanced review requested due to automatic review settings August 6, 2026 21:53

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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Note

This error may be related to your runner configuration. You can now configure runners for Copilot code review separately from Copilot cloud agent by creating a copilot-code-review.yml file with your setup steps. Read the docs for details.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 19082

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 19082"

Classify explicit AppHost directories containing only unbuildable candidates as build failures, and add unit and CLI regression coverage for the missing-SDK case.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 0f00829a-32fc-44f6-bfb8-4310c86a460c
Copilot AI review requested due to automatic review settings August 6, 2026 23:01

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.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/Aspire.Cli/Commands/RunCommand.cs:589

  • The new build_failed telemetry classification is not covered by the added tests: the locator tests stop at the exception/exit-code mapping, and the E2E test only checks terminal output. Since RunCommandTests already verifies ErrorType tags, add a case whose locator throws AppHostsMayNotBeBuildable and assert that the run activity records build_failed; otherwise this advertised telemetry behavior can regress without any test failing.
            runActivity?.SetTag(
                TelemetryConstants.Tags.ErrorType,
                ex.FailureReason is ProjectLocatorFailureReason.AppHostsMayNotBeBuildable ? "build_failed" : "project_not_found");

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

…n failure

An AppHost can exist and still fail MSBuild evaluation, most commonly when
Aspire.AppHost.Sdk cannot be resolved. ProjectLocator treated that signal
(IsPossiblyUnbuildable) as "no such project", so the user was told the file did
not exist, or that no AppHosts were found, and never saw the MSB4236 that
explained the real problem.

Keep the selection instead. An explicitly named file, an explicitly named
directory holding one candidate, and a configured aspire.config.json path are
all deliberate user choices, so honor them and let the command's existing build
path print the diagnostics it already collects. That path needs no changes: it
already stashes build output, reports FailedToBuildArtifacts, and displays the
collected lines.

Ambient discovery is deliberately unchanged. Finding only unbuildable
candidates while scanning is still AppHostsMayNotBeBuildable with
FailedToFindProject, because AppHostConnectionResolver.IsProjectResolutionError
keys off that exit code to tell "AppHost not running" apart from "no project
resolved". Remapping it makes stop/logs/describe/ps emit success-shaped output.

An unverified selection is never written back to settings, since a candidate
kept only because MSBuild failed was never confirmed to be an AppHost and would
otherwise be silently reused by later ambient invocations.

Fixes microsoft#19035

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c56ab082-7689-4734-9d39-dbca4d4e1470

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.

Review details

Suppressed comments (1)

src/Aspire.Cli/Projects/ProjectLocator.cs:604

  • On case-sensitive macOS volumes, OrdinalIgnoreCase treats sibling directories such as Services and services as the same subtree. Because discovery injects candidates from parent configuration, --apphost ./Services can therefore auto-select an unverified configured project under ./services, defeating the containment check this helper was added to enforce. Please determine case sensitivity for the actual volume (or compare filesystem identity) rather than assuming all macOS paths are case-insensitive.
        var pathComparison = environment.IsWindows() || environment.IsMacOS()
            ? StringComparison.OrdinalIgnoreCase
            : StringComparison.Ordinal;
  • Files reviewed: 7/7 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[main] VS Code (CLI?) incorrectly reports "The --apphost option specified a project that does not exist." if an apphost fails to build

2 participants