microsoft/aspire · error · ArgumentException

The requiredBy parameter must be a string or IEnumerable

Error message

The requiredBy parameter must be a string or IEnumerable<string>, but was {requiredBy.GetType().Name}.

What it means

The pipeline's AddRequiredBy helper (invoked from AddStep) accepts only a single step name (string) or a collection of step names (IEnumerable<string>) for the 'requiredBy' parameter. Passing any other object type (e.g., a char, a single-element non-enumerable type, or a boxed value) is rejected with this ArgumentException because the library cannot interpret it as step-name data. It is a defensive argument-validation failure.

Solutions

  1. Inspect the value passed as requiredBy and ensure it is a string or an IEnumerable<string> (e.g., new[]{"StepA", "StepB"}).
  2. If passing a single step name, add .ToString() or wrap the literal in double quotes instead of single quotes (C# char vs string).
  3. If passing a collection of another element type, map it to strings first: requiredBy.Select(x => x.ToString()).
  4. Check whether a config deserializer produced a non-string type (e.g., JValue, JsonElement) and convert with value.GetValue<string>() or value.ToString() before calling AddStep.

Example fix

// before
var step = new PipelineStep("deploy") { RequiredBy = 'publish' };
// after
var step = new PipelineStep("deploy") { RequiredBy = new[] { "publish" } };
Defensive patterns

Strategy: type-guard

Validate before calling

bool IsValidRequiredBy(object? requiredBy) =>
    requiredBy is string or IEnumerable<string>;

Type guard

static bool IsStringOrStringEnumerable(object? value) =>
    value is string || (value is IEnumerable<object> seq && seq.All(item => item is string));

Try / catch

try
{
    pipeline.AddStep(step);
}
catch (ArgumentException ex) when (ex.ParamName == nameof(requiredBy))
{
    logger.LogError(ex, "requiredBy must be string or IEnumerable<string>, was {Type}", step.RequiredBy?.GetType().Name);
}

Prevention

When it happens

Trigger: Calling DistributedApplicationPipeline.AddStep with a PipelineStep whose RequiredBy parameter was supplied as an unsupported type - e.g., a char ('a' instead of "a"), a HashSet, or any object not implementing IEnumerable<string> - so the type switch in AddRequiredBy falls to the else branch.

Common situations: Hand-writing pipeline step registrations where a single character literal is passed instead of a string; using a collection type that does not implement IEnumerable<string> (e.g., List<int> of step indexes); refactoring code that changed a string parameter to a custom type; copy-pasting requiredBy values from a config where types are loosely parsed.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

        }
    }

    private static void AddRequiredBy(PipelineStep step, object requiredBy)
    {
        if (requiredBy is string stepName)
        {
            step.RequiredBy(stepName);
        }
        else if (requiredBy is IEnumerable<string> stepNames)
        {
            foreach (var name in stepNames)
            {
                step.RequiredBy(name);
            }
        }
        else
        {
            throw new ArgumentException(
                $"The requiredBy parameter must be a string or IEnumerable<string>, but was {requiredBy.GetType().Name}.",
                nameof(requiredBy));
        }
    }

    public void AddStep(PipelineStep step)
    {
        if (_steps.Any(s => s.Name == step.Name))
        {
            throw new InvalidOperationException(
                $"A step with the name '{step.Name}' has already been added to the pipeline.");
        }

        _steps.Add(step);
    }

    public void AddPipelineConfiguration(Func<PipelineConfigurationContext, Task> callback)
    {

View on GitHub (pinned to 25830f84bd)