Skip to content

aspire publish --publisher docker-compose crashes with 'Sequence contains more than one matching element' #17392

@javiercn

Description

@javiercn

Is there an existing issue for this?

  • 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:

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions