microsoft/aspire · error · InvalidOperationException

Resource ' ' project metadata was replaced after project…

Error message

Resource '{resource.Name}' project metadata was replaced after project defaults were applied. Project metadata must remain unchanged after WithProjectDefaults configures the resource.

What it means

ProjectLaunchDefaultsAnnotation captures a reference to the IProjectMetadata instance present when WithProjectDefaults ran and re-validates it later via ValidateProjectMetadata. If the resource's project metadata annotation was replaced by a different instance, the defaults may no longer correspond to the project, so it throws InvalidOperationException.

Solutions

  1. Do not replace IProjectMetadata after WithProjectDefaults; configure the project path before defaults are applied
  2. If metadata must change, apply WithProjectDefaults again after the change (recreating the defaults annotation)
  3. Use TryGetAnnotations to detect existing metadata before adding a new one

Example fix

// before
builder.WithAnnotation(new ProjectMetadata { ProjectPath = otherPath }); // after defaults applied
// after
// set the project path BEFORE calling WithProjectDefaults
builder.WithAnnotation(new ProjectMetadata { ProjectPath = otherPath });
builder.WithProjectDefaults();
Defensive patterns

Strategy: validation

Validate before calling

// after WithProjectDefaults, verify metadata is still the applied instance
annotation.ValidateProjectMetadata(resource, metadata); // call defensively before launch resolution

Try / catch

try { annotation.ValidateProjectMetadata(resource, metadata); } catch (InvalidOperationException) { /* re-apply WithProjectDefaults */ }

Prevention

When it happens

Trigger: Calling WithProjectDefaults and then adding/removing/replacing the resource's IProjectMetadata annotation (e.g. re-adding metadata with a different ProjectPath) before launch configuration resolution.

Common situations: Custom builder extensions that unconditionally AddAnnotation a new ProjectMetadata, duplicating or replacing the original; rebuilding a resource and re-applying metadata; copying annotations between resources.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting/ApplicationModel/ProjectLaunchDefaultsAnnotation.cs:63

    internal bool TrySetAppliedProjectMetadata(IProjectMetadata projectMetadata)
    {
        if (_appliedProjectMetadata is not null)
        {
            return false;
        }

        _appliedProjectMetadata = projectMetadata;
        return true;
    }

    /// <summary>
    /// Validates that project metadata has not changed since project defaults were materialized.
    /// </summary>
    internal void ValidateProjectMetadata(IResource resource, IProjectMetadata projectMetadata)
    {
        if (_appliedProjectMetadata is not null && !ReferenceEquals(projectMetadata, _appliedProjectMetadata))
        {
            throw new InvalidOperationException(
                $"Resource '{resource.Name}' project metadata was replaced after project defaults were applied. " +
                $"Project metadata must remain unchanged after {nameof(ProjectResourceBuilderExtensions.WithProjectDefaults)} configures the resource.");
        }
    }
}

internal static class ProjectLaunchDefaultsExtensions
{
    /// <summary>
    /// Determines whether endpoint environment variables should be injected for the given endpoint.
    /// Only http/https endpoints without an explicit target-port environment variable are eligible,
    /// and any <see cref="EndpointEnvironmentInjectionFilterAnnotation"/> may further exclude them.
    /// </summary>
    [AspireExportIgnore(Reason = "Endpoint environment injection filtering is internal .NET launch wiring and is not part of the ATS surface.")]
    public static bool ShouldInjectEndpointEnvironment(this IResource resource, EndpointReference e)
    {
        var endpoint = e.EndpointAnnotation;

View on GitHub (pinned to 25830f84bd)