microsoft/aspire · error · InvalidOperationException

Duplicate step name

Error message

Duplicate step name: '{step.Name}'

What it means

The Aspire application model pipeline validates that every pipeline step has a unique name before executing. During ResolveStepsAsync, ValidateSteps adds each step name to an ordinal HashSet; a duplicate add means two steps registered with the same name, which would make dependency references ambiguous, so an InvalidOperationException is thrown before any step runs.

Solutions

  1. Find the second registration of the step with the duplicated name and remove it or guard it so it runs only once
  2. Make step names unique by incorporating the resource/identifier, e.g. $"{resource.Name}-deploy" instead of a constant
  3. If an extension method may be called multiple times, have it check whether a step with that name already exists before adding
  4. Update the dependency references (DependsOnSteps/RequiredBySteps) that pointed at the old shared name to point at the new unique names

Example fix

// before
builder.Pipeline.AddStep("deploy", ...);
foreach (var r in resources) { builder.Pipeline.AddStep("deploy", ...); }
// after
foreach (var r in resources) { builder.Pipeline.AddStep($"deploy-{r.Name}", ...); }
Defensive patterns

Strategy: validation

Validate before calling

var names = new HashSet<string>(StringComparer.Ordinal);
foreach (var step in pipeline.Steps)
{
    if (!names.Add(step.Name))
        throw new InvalidOperationException($"Duplicate step name registered: '{step.Name}'");
}

Try / catch

try { await app.RunAsync(); }
catch (InvalidOperationException ex) when (ex.Message.StartsWith("Duplicate step name:"))
{
    // fix the duplicated step registration indicated in ex.Message
}

Prevention

When it happens

Trigger: Two or more IHostingPipelineStep implementations (or AddStep calls) registered with the identical Name string into the same DistributedApplicationPipeline; also occurs when an integration is added twice (e.g. two AddXxx calls each contributing a step with the same fixed name) or a step is registered per-resource with a constant name instead of including the resource name.

Common situations: Calling an integration extension method twice on the same builder when it unconditionally adds a fixed-name step; copying sample code that adds the same custom step twice; a loop over resources that registers a step named after the type rather than the resource; two different packages each contributing a step with a colliding name.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting/Pipelines/DistributedApplicationPipeline.cs:815

                Model = pipelineContext.Model
            };

            foreach (var callback in callbacks)
            {
                await callback(configContext).ConfigureAwait(false);
            }
        }
    }

    private static void ValidateSteps(IEnumerable<PipelineStep> steps)
    {
        var stepNames = new HashSet<string>(StringComparer.Ordinal);

        foreach (var step in steps)
        {
            if (!stepNames.Add(step.Name))
            {
                throw new InvalidOperationException(
                    $"Duplicate step name: '{step.Name}'");
            }
        }

        foreach (var step in steps)
        {
            foreach (var dependency in step.DependsOnSteps)
            {
                if (!stepNames.Contains(dependency))
                {
                    throw new InvalidOperationException(
                        $"Step '{step.Name}' depends on unknown step '{dependency}'");
                }
            }

            foreach (var requiredBy in step.RequiredBySteps)
            {
                if (!stepNames.Contains(requiredBy))

View on GitHub (pinned to 25830f84bd)