microsoft/aspire · error · ProjectUpdaterException

Could not find '#:sdk Aspire.AppHost.Sdk@

Error message

Could not find '#:sdk Aspire.AppHost.Sdk@<version>' directive in single-file AppHost: {0}

What it means

Single-file AppHosts (.cs) declare their SDK with a file directive `#:sdk Aspire.AppHost.Sdk@<version>`. UpdateSdkVersionInSingleFileAppHostAsync regex-matches that directive; if no line matches, it cannot update the SDK version and throws ProjectUpdaterException.

Solutions

  1. Add or restore the directive at the top of the .cs AppHost: `#:sdk Aspire.AppHost.Sdk@<current-version>`, then re-run `aspire update`.
  2. Check spelling/casing: the directive must be exactly `#:sdk Aspire.AppHost.Sdk@` followed by a version.
  3. Edit the version in the directive manually if you prefer to skip the updater for this file.

Example fix

// before (top of apphost.cs)
#:project
// after
#:sdk Aspire.AppHost.Sdk@9.4.0
Defensive patterns

Strategy: validation

Validate before calling

var content = File.ReadAllText(singleFileAppHost);
if (!System.Text.RegularExpressions.Regex.IsMatch(content, "#:sdk Aspire\.AppHost\.Sdk@[^\s]+"))
    throw new InvalidOperationException($"{singleFileAppHost} lacks the #:sdk Aspire.AppHost.Sdk@<version> directive.");

Try / catch

try { await updater.UpdateAsync(...); }
catch (ProjectUpdaterException ex) when (ex.Message.Contains("#:sdk Aspire.AppHost.Sdk"))
{
    // add the directive at the top of the file, then re-run update
}

Prevention

When it happens

Trigger: Updating a single-file AppHost whose content lacks a `#:sdk Aspire.AppHost.Sdk@<version>` directive — e.g. directive deleted, different SDK name, wrong @ separator, or the .cs file isn't actually a single-file AppHost.

Common situations: Hand-edited single-file AppHost where the directive was removed or reformatted (e.g. `#:sdk aspire.apphost.sdk@9.0.0` casing mismatch); an older single-file layout predating the directive convention; a plain .cs file misidentified as an AppHost.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Cli/Projects/ProjectUpdater.cs:881

                    "removed from '{1}': {2}. Please manually remove the <PackageVersion Include=\"{0}\" ... /> " +
                    "entry from this file to avoid NU1009 build errors.",
                    packageId,
                    cpmInfo.DirectoryPackagesPropsFile.FullName,
                    ex.Message),
                ex);
        }
    }

    private static async Task UpdateSdkVersionInSingleFileAppHostAsync(FileInfo projectFile, NuGetPackageCli package)
    {
        var fileContent = await File.ReadAllTextAsync(projectFile.FullName);

        // Look for the #:sdk Aspire.AppHost.Sdk@<version> directive
        var match = SdkDirectiveRegex().Match(fileContent);

        if (!match.Success)
        {
            throw new ProjectUpdaterException(string.Format(CultureInfo.InvariantCulture,
                "Could not find '#:sdk Aspire.AppHost.Sdk@<version>' directive in single-file AppHost: {0}", projectFile.FullName));
        }

        // Replace the matched SDK directive with the new version
        var newDirective = $"#:sdk Aspire.AppHost.Sdk@{package.Version}";
        var updatedContent = SdkDirectiveRegex().Replace(fileContent, newDirective, 1);

        // The new SDK pulls Aspire.Hosting.AppHost in implicitly, so a leftover
        // explicit `#:package Aspire.Hosting.AppHost@<version>` directive in the
        // same file is redundant. Strip it here so the SDK-bump path matches
        // the csproj migration in UpdateSdkVersionInProjectAppHostAsync. The
        // SDK-already-current path goes through EnqueueLegacyAppHostCleanupStepIfNeeded.
        updatedContent = LegacyAppHostPackageDirectiveRegex().Replace(updatedContent, string.Empty);

        await File.WriteAllTextAsync(projectFile.FullName, updatedContent);
    }

    [GeneratedRegex(@"#:sdk\s+Aspire\.AppHost\.Sdk@(?:[\d\.\-a-zA-Z]+|\*)")]

View on GitHub (pinned to 25830f84bd)