microsoft/aspire · error · ProjectLocatorException
Multiple project files found.
Error message
Multiple project files found.
What it means
When multiple AppHost project files are found in one directory and the caller configured MultipleAppHostProjectsFoundBehavior.Throw, ProjectLocator refuses to guess and throws ProjectLocatorException with ErrorStrings.MultipleProjectFilesFound and reason MultipleProjectFilesFound. The behavior is a contract: callers who cannot prompt the user for a choice explicitly request an exception instead of ambiguous selection.
Solutions
- Pass --project <path> to explicitly select which AppHost to use, bypassing ambiguity.
- Remove or move the extra AppHost projects so only one remains in the directory.
- Use a MultipleAppHostProjectsFoundBehavior that fits the context (interactive selection instead of Throw) if prompting is acceptable.
- Catch ProjectLocatorException with FailureReason MultipleProjectFilesFound and enumerate the candidates for the user.
Example fix
// before aspire run # multiple AppHosts in ./src, Throw behavior // after aspire run --project ./src/AppHost1/AppHost1.csproj
Defensive patterns
Strategy: try-catch
Validate before calling
var appHosts = Directory.EnumerateFiles(dir, "*.csproj", SearchOption.AllDirectories)
.Where(p => File.ReadAllText(p).Contains("Aspire.AppHost.Sdk"))
.ToList();
if (appHosts.Count > 1) Console.WriteLine("Multiple AppHosts found: " + string.Join(", ", appHosts) + " — pass --project to disambiguate."); Type guard
static bool IsAmbiguousAppHostDirectory(string dir) => Directory.EnumerateFiles(dir, "*.csproj", SearchOption.AllDirectories).Count(LooksLikeAppHost) > 1;
Try / catch
try { var appHost = await locator.UseAppHostAsync(ct); }
catch (ProjectLocatorException ex) when (ex.FailureReason == ProjectLocatorFailureReason.MultipleProjectFilesFound)
{ Console.WriteLine("Multiple AppHosts found — re-run with --project <csproj> to choose one."); } Prevention
- Keep one AppHost project per scanned directory; move extras elsewhere.
- Always pass --project in non-interactive/CI contexts.
- Choose MultipleAppHostProjectsFoundBehavior matching the environment (Throw for automation, selection for interactive).
- Handle the MultipleProjectFilesFound failure reason explicitly in scripts to list candidates.
When it happens
Trigger: Multiple AppHost csproj files in the same scanned directory combined with MultipleAppHostProjectsFoundBehavior.Throw (typically in non-interactive/automation contexts where prompting is impossible).
Common situations: Merging several samples into one folder; copying a second AppHost project next to an existing one; scaffolding tools generating extra AppHost projects; CI scripts running in a directory with multiple AppHosts where interactive selection is unavailable.
Related errors
- InternalError
- No buildable AppHosts were found, but there may have been…
- No project file found.
- Project file does not exist.
- AppHost is incompatible with the CLI. The AppHost must be…
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/3dc4787f6acb4fa4.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Cli/Projects/ProjectLocator.cs:982
{
logger.LogDebug("Multiple AppHost project files found in directory {Directory}, prompting user to select", directory.FullName);
explicitSelectionWasPrompted = true;
projectFile = await interactionService.PromptForSelectionAsync(
InteractionServiceStrings.SelectAppHostToUse,
appHostProjects,
file => $"{file.Name.EscapeMarkup()} ({Path.GetRelativePath(executionContext.WorkingDirectory.FullName, file.FullName).EscapeMarkup()})",
cancellationToken: cancellationToken
);
}
else if (multipleAppHostProjectsFoundBehavior is MultipleAppHostProjectsFoundBehavior.None)
{
logger.LogDebug("Multiple AppHost project files found in directory {Directory}, selecting none", directory.FullName);
return new AppHostProjectSearchResult(null, appHostProjects);
}
else if (multipleAppHostProjectsFoundBehavior is MultipleAppHostProjectsFoundBehavior.Throw)
{
logger.LogError("Multiple AppHost project files found in directory {Directory}, throwing exception", directory.FullName);
throw new ProjectLocatorException(ErrorStrings.MultipleProjectFilesFound, ProjectLocatorFailureReason.MultipleProjectFilesFound);
}
}
}
else if (File.Exists(projectFile.FullName))
{
// A project file was directly specified.
//
// Preserve symlinks because single-file AppHosts load apphost.run.json and
// aspire.config.json beside the selected path. Backchannel and comparison call
// sites canonicalize their own identity keys.
var resolvedProjectPath = PathNormalizer.ResolvePathCasing(projectFile.FullName);
if (!string.Equals(resolvedProjectPath, projectFile.FullName, StringComparison.Ordinal))
{
logger.LogDebug(
"Normalized explicit AppHost path casing from '{OriginalPath}' to '{ResolvedPath}'.",
projectFile.FullName,
resolvedProjectPath);View on GitHub (pinned to 25830f84bd)