microsoft/aspire · error · InvalidOperationException

Cannot update task ' ' because its parent step ' ' is…

Error message

Cannot update task '{task.Id}' because its parent step '{task.StepId}' is already complete.

What it means

UpdateTaskAsync only allows status updates while the parent step is InProgress. Under the step's lock, if parentStep.CompletionState has left InProgress, the reporter throws InvalidOperationException: once a step completed, its task status text is final and late updates would misrepresent the recorded result.

Solutions

  1. Ensure the step is only completed after all task updates finish; await updates before CompleteStepAsync.
  2. Check parentStep.CompletionState before updating, or catch InvalidOperationException and treat the update as dropped.
  3. Avoid fire-and-forget update loops; use completion callbacks to stop updates when the step completes.
  4. Restructure so terminal errors also route through task updates before completing the step.

Example fix

// before
_ = Task.Run(async () => { while (true) await reporter.UpdateTaskAsync(task, progress, false); });
// after
while (task.CompletionState == CompletionState.InProgress)
    await reporter.UpdateTaskAsync(task, progress, false);
Defensive patterns

Strategy: try-catch

Validate before calling

if (parentStep?.CompletionState != CompletionState.InProgress) return;

Type guard

bool CanUpdateTask(ReportingTask task) => task.CompletionState == CompletionState.InProgress;

Try / catch

try { await reporter.UpdateTaskAsync(task, text, false); } catch (InvalidOperationException ex) when (ex.Message.Contains("already complete")) { logger.LogDebug("Step already complete; final status kept."); }

Prevention

When it happens

Trigger: Calling UpdateTaskAsync after the parent step was completed (CompleteStepAsync with success/error/warning) — e.g. a background task streaming progress while an error handler already completed the step.

Common situations: Cancellation/error paths that complete a step while worker tasks still push progress updates; fire-and-forget update loops not observing step completion; slow status flushes racing step completion in publish pipelines.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting/Pipelines/PipelineActivityReporter.cs:153

            Type = PublishingActivityTypes.Step,
            Data = CreateStepActivityData(step, completionText, completionState, enableMarkdown)
        };

        await ActivityItemUpdated.Writer.WriteAsync(state, cancellationToken).ConfigureAwait(false);
    }

    public async Task UpdateTaskAsync(ReportingTask task, string statusText, bool enableMarkdown, CancellationToken cancellationToken)
    {
        if (!_steps.TryGetValue(task.StepId, out var parentStep))
        {
            throw new InvalidOperationException($"Parent step with ID '{task.StepId}' does not exist.");
        }

        lock (parentStep)
        {
            if (parentStep.CompletionState != CompletionState.InProgress)
            {
                throw new InvalidOperationException($"Cannot update task '{task.Id}' because its parent step '{task.StepId}' is already complete.");
            }

            task.StatusText = statusText;
        }

        var state = new PublishingActivity
        {
            Type = PublishingActivityTypes.Task,
            Data = new PublishingActivityData
            {
                Id = task.Id,
                StatusText = statusText,
                CompletionState = ToBackchannelCompletionState(CompletionState.InProgress),
                StepId = task.StepId,
                EnableMarkdown = enableMarkdown
            }
        };

View on GitHub (pinned to 25830f84bd)