Is there an existing issue for this?
Describe the bug
Running aspire publish --publisher docker-compose on any project with AddDockerComposeEnvironment fails with an InvalidOperationException because PrepareDeploymentTargetsAsync adds duplicate DeploymentTargetAnnotation entries to compute resources.
From my investigation, it appears that the prepare-deployment-targets-{name} pipeline step executes twice during a publish:
- Once during
ExecuteStepSequentiallyAsync("before-start", ...) in DistributedApplication.StartAsync (because the step declares RequiredBySteps = [BeforeStart] and is included in the transitive dependency closure)
- Again during the main
ExecuteAsync DAG execution in PipelineExecutor
Both runs share the same DistributedApplicationModel, so the second execution adds duplicate annotations to resources that were already annotated in the first pass.
Note: I'm not 100% certain this isn't something I'm doing wrong in my AppHost configuration. It's possible there's a setup step I'm missing or a configuration that would prevent the double-execution. However, I've reproduced this with a minimal AppHost that has nothing beyond AddDockerComposeEnvironment and a single project resource.
Expected Behavior
aspire publish --publisher docker-compose should complete successfully, producing a docker-compose.yaml with all compute resources.
Steps To Reproduce
Minimal AppHost:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddDockerComposeEnvironment("docker-compose")
.WithProperties(env => env.DashboardEnabled = false);
builder.AddProject<Projects.MyApi>("api");
builder.Build().Run();
Run:
dotnet run -- publish --publisher docker-compose --output-path ./output
Exceptions (if any)
System.InvalidOperationException: Sequence contains more than one matching element
at System.Linq.ThrowHelper.ThrowMoreThanOneMatchException()
at System.Linq.Enumerable.SingleOrDefault[TSource](...)
at Aspire.Hosting.ApplicationModel.ResourceExtensions.GetDeploymentTargetAnnotation(IResource resource, IComputeEnvironment computeEnvironment)
at Aspire.Hosting.Docker.DockerComposeEnvironmentResource.<>c__DisplayClass...(PipelineStepContext context)
.NET Version info
.NET 10.0 (main branch, as of May 2026)
Anything else?
Workaround: Adding an idempotency guard at the top of PrepareDeploymentTargetsAsync in DockerComposeEnvironmentResource.cs resolves the issue:
private bool _deploymentTargetsPrepared;
private async Task PrepareDeploymentTargetsAsync(PipelineStepContext context)
{
if (executionContext.IsRunMode) return;
if (_deploymentTargetsPrepared) return;
_deploymentTargetsPrepared = true;
// ... rest of method
}
The issue is in src/Aspire.Hosting.Docker/DockerComposeEnvironmentResource.cs, specifically the step registered at line 68-75 which unconditionally adds DeploymentTargetAnnotation on each invocation.
Is there an existing issue for this?
Describe the bug
Running
aspire publish --publisher docker-composeon any project withAddDockerComposeEnvironmentfails with anInvalidOperationExceptionbecausePrepareDeploymentTargetsAsyncadds duplicateDeploymentTargetAnnotationentries to compute resources.From my investigation, it appears that the
prepare-deployment-targets-{name}pipeline step executes twice during a publish:ExecuteStepSequentiallyAsync("before-start", ...)inDistributedApplication.StartAsync(because the step declaresRequiredBySteps = [BeforeStart]and is included in the transitive dependency closure)ExecuteAsyncDAG execution inPipelineExecutorBoth runs share the same
DistributedApplicationModel, so the second execution adds duplicate annotations to resources that were already annotated in the first pass.Note: I'm not 100% certain this isn't something I'm doing wrong in my AppHost configuration. It's possible there's a setup step I'm missing or a configuration that would prevent the double-execution. However, I've reproduced this with a minimal AppHost that has nothing beyond
AddDockerComposeEnvironmentand a single project resource.Expected Behavior
aspire publish --publisher docker-composeshould complete successfully, producing adocker-compose.yamlwith all compute resources.Steps To Reproduce
Minimal AppHost:
Run:
Exceptions (if any)
.NET Version info
.NET 10.0 (main branch, as of May 2026)
Anything else?
Workaround: Adding an idempotency guard at the top of
PrepareDeploymentTargetsAsyncinDockerComposeEnvironmentResource.csresolves the issue:The issue is in
src/Aspire.Hosting.Docker/DockerComposeEnvironmentResource.cs, specifically the step registered at line 68-75 which unconditionally addsDeploymentTargetAnnotationon each invocation.