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
- Do not replace IProjectMetadata after WithProjectDefaults; configure the project path before defaults are applied
- If metadata must change, apply WithProjectDefaults again after the change (recreating the defaults annotation)
- 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
- Set project metadata before calling WithProjectDefaults and never touch it afterwards
- Avoid unconditional AddAnnotation of ProjectMetadata in custom extensions
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
- Cannot register migrations without a context type when they…
- Resource ' ' carries more than one IProjectMetadata…
- Resource ' ' does not carry an IProjectMetadata annotation.
- Resource ' ' cannot produce a " " launch configuration…
- Already connected to
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)