microsoft/aspire · error · DistributedApplicationException

Path to C# project could not be determined. The directory

Error message

Path to C# project could not be determined. The directory '{projectPath}' must contain a single .csproj file.

What it means

AddCSharpApp throws DistributedApplicationException when the supplied project path is not a .csproj or .cs file and, if it is a directory, that directory does not contain exactly one .csproj file. The message distinguishes two cases: the path exists as a directory without a single .csproj, or the path is otherwise invalid (not a .cs/.csproj file or usable directory). Aspire cannot determine which project to run, so it fails during resource callback validation.

Solutions

  1. Pass the full path to the specific .csproj (or the .cs entry file) directly.
  2. If passing a directory, ensure it contains exactly one .csproj file; move or exclude extra project files.
  3. Fix path typos and verify the path exists relative to the AppHost's working directory.
  4. Move shared class libraries out of the target directory or reference them explicitly instead.

Example fix

// before
builder.AddCSharpApp("frontend", "../frontend"); // directory has 2 .csproj files

// after
builder.AddCSharpApp("frontend", "../frontend/Frontend.csproj");
Defensive patterns

Strategy: validation

Validate before calling

var resolved = Path.GetFullPath(projectPath);
if (!resolved.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase) &&
    !resolved.EndsWith(".cs", StringComparison.OrdinalIgnoreCase) &&
    Directory.EnumerateFiles(resolved, "*.csproj").Take(2).Count() != 1)
{
    throw new DistributedApplicationException($"'{projectPath}' must be a .csproj, a .cs file, or a directory with exactly one .csproj.");
}

Try / catch

try
{
    builder.AddCSharpApp(name, projectPath);
}
catch (DistributedApplicationException ex) when (ex.Message.Contains("Path to C# project could not be determined"))
{
    logger.LogError(ex, "Project path '{Path}' does not resolve to a single .csproj.", projectPath);
}

Prevention

When it happens

Trigger: Calling builder.AddCSharpApp("name", path) with a directory containing zero or multiple .csproj files; or with a path not ending in .csproj/.cs that is not a directory; or a mistyped path.

Common situations: Pointing at a solution folder or multi-project directory, typos in the path, passing a directory that holds several projects, or using a relative path that resolves differently from the AppHost working directory.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/e719a294cefa738f. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting/ProjectResourceBuilderExtensions.cs:434

        path = PathNormalizer.NormalizePathForCurrentPlatform(Path.Combine(builder.AppHostDirectory, path));
        var projectMetadata = new ProjectMetadata(path);

        var resource = builder.AddResource(app)
                              .WithAnnotation(projectMetadata)
                              .WithProjectDefaults(options);

        resource.OnBeforeResourceStarted((r, e, ct) =>
        {
            var projectPath = projectMetadata.ProjectPath;

            // Validate project path
            if (!projectPath.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase) && !projectPath.EndsWith(".cs", StringComparison.OrdinalIgnoreCase))
            {
                // Project path did not resolve to a .csproj or .cs file
                var message = Directory.Exists(projectPath)
                    ? $"Path to C# project could not be determined. The directory '{projectPath}' must contain a single .csproj file."
                    : $"The C# app path '{projectPath}' is invalid. The path must be to a .cs file, .csproj file, or directory containing a single .csproj file.";
                throw new DistributedApplicationException(message);
            }

            return Task.CompletedTask;
        });

        return resource;
    }

    private static void ApplyProjectResourceOptions(ProjectResourceOptions target, ProjectResourceOptions source)
    {
        ArgumentNullException.ThrowIfNull(target);
        ArgumentNullException.ThrowIfNull(source);

        target.LaunchProfileName = source.LaunchProfileName;
        target.ExcludeLaunchProfile = source.ExcludeLaunchProfile;
        target.ExcludeKestrelEndpoints = source.ExcludeKestrelEndpoints;
    }

View on GitHub (pinned to 25830f84bd)