aspire publish --publisher docker-compose crashes with 'Sequence contains more than one matching element'
- Dominant language
- C#
- Stars
- 6.3k
- Forks
- 991
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 196
Description
### Is there an existing issue for this?
- [x] I have searched the existing issues
### 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:
1. Once during `ExecuteStepSequentiallyAsync("before-start", ...)` in `DistributedApplication.StartAsync` (because the step declares `RequiredBySteps = [BeforeStart]` and is included in the transitive dependency closure)
2. 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:
```csharp
var builder = DistributedApplication.CreateBuilder(args);
builder.AddDockerComposeEnvironment("docker-compose")
.WithProperties(env => env.DashboardEnabled = false);
builder.AddProject("api");
builder.Build().Run();
```
Run:
```bash
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:
```csharp
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.
Contributor guide
Assessment
This issue has not been assessed yet.