microsoft/aspire · error · InvalidOperationException
Step ' ' is required by unknown step
Error message
Step '{step.Name}' is required by unknown step '{requiredByStep}' What it means
Before execution, NormalizeRequiredByToDependsOn converts every step's RequiredBySteps (inverse relationships) into forward DependsOnSteps entries. If a step declares RequiredBy("SomeStep") but no step named SomeStep exists in the pipeline, the graph would be left dangling, so the pipeline throws this InvalidOperationException naming both the declaring step and the unknown required-by step.
Solutions
- Ensure a step with the exact requiredBy name is added to the same pipeline (check spelling against the registered step names).
- Remove or guard the RequiredBy call when the dependency step is optional/conditional.
- Centralize step-name constants (e.g., a static class of known step names) so RequiredBy and AddStep reference the same values.
- Audit conditional registration paths so that any step referenced via RequiredBy is registered unconditionally or its dependents are too.
Example fix
// before
pipeline.AddStep(buildStep);
buildStep.RequiredBy("publish"); // 'publish' never added
// after
pipeline.AddStep(buildStep);
pipeline.AddStep(new PipelineStep("publish"));
buildStep.RequiredBy("publish"); Defensive patterns
Strategy: validation
Validate before calling
var declared = steps.SelectMany(s => s.RequiredBySteps).Distinct();
var known = steps.Select(s => s.Name).ToHashSet(StringComparer.Ordinal);
var unknown = declared.Where(n => !known.Contains(n)).ToList();
if (unknown.Count > 0)
{
throw new InvalidOperationException($"RequiredBy references unknown steps: {string.Join(", ", unknown)}");
} Try / catch
try
{
await pipeline.ExecuteAsync(context);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("is required by unknown step"))
{
logger.LogError(ex, "A RequiredBy declaration names a step that was never added to the pipeline.");
} Prevention
- Define step names in a shared constants class used by both AddStep and RequiredBy.
- Never declare RequiredBy against a step that is conditionally registered.
- Validate the full graph (declared vs registered names) in tests before execution.
- When renaming a step, update all RequiredBy references in the same change.
When it happens
Trigger: Calling step.RequiredBy("name") (directly or via AddStep's requiredBy parameter) for a step name that is never registered on the same pipeline - e.g., the required-by step was added to a different pipeline, renamed, or conditionally registered in a path that did not run.
Common situations: Modular pipelines where feature A declares RequiredBy("deploy") assuming another module adds 'deploy', but that module was disabled; typos in requiredBy strings; steps renamed during refactoring while RequiredBy strings stayed stale; ordering issues where RequiredBy is registered before the conditional AddStep of the other step (the check happens at execution, so absence - not order - triggers it).
Understand the failure class
Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.
Related errors
- A step with the name
- Circular dependency detected in pipeline steps
- Step ' ' not found in pipeline. Available steps
- The requiredBy parameter must be a string or IEnumerable
- Array params contains empty item
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/4fb1c1a370a0e9bd.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting/Pipelines/DistributedApplicationPipeline.cs:665
return allSteps;
}
/// <summary>
/// Converts all RequiredBy relationships to their equivalent DependsOn relationships.
/// If step A is required by step B, this adds step A as a dependency of step B.
/// </summary>
private static void NormalizeRequiredByToDependsOn(
List<PipelineStep> steps,
Dictionary<string, PipelineStep> stepsByName)
{
foreach (var step in steps)
{
foreach (var requiredByStep in step.RequiredBySteps)
{
if (!stepsByName.TryGetValue(requiredByStep, out var requiredByStepObj))
{
throw new InvalidOperationException(
$"Step '{step.Name}' is required by unknown step '{requiredByStep}'");
}
// Add the inverse relationship: if step A is required by step B,
// then step B depends on step A
if (!requiredByStepObj.DependsOnSteps.Contains(step.Name))
{
requiredByStepObj.DependsOnSteps.Add(step.Name);
}
}
}
}
private static (List<PipelineStep> StepsToExecute, Dictionary<string, PipelineStep> StepsByName) FilterStepsForExecution(
List<PipelineStep> allSteps,
PipelineContext context)
{
var pipelineOptions = context.Services.GetService<Microsoft.Extensions.Options.IOptions<PipelineOptions>>();View on GitHub (pinned to 25830f84bd)