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
- Ensure the step is only completed after all task updates finish; await updates before CompleteStepAsync.
- Check parentStep.CompletionState before updating, or catch InvalidOperationException and treat the update as dropped.
- Avoid fire-and-forget update loops; use completion callbacks to stop updates when the step completes.
- 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
- Stop update loops when the step signals completion
- Complete the step only after all pending updates are awaited
- Route terminal errors through task updates before step completion
- Avoid background tasks writing status after step completion
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
- Cannot complete task
- Cannot create task for step
- Parent step with ID ' ' does not exist.
- Step with ID ' ' does not exist.
- The MAUI OTLP dev tunnel configuration was not initialized…
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)