{"record":{"id":"b9f7e4508728f41e","repo":"microsoft/aspire","slug":"cannot-update-task-task-id-because-its-parent-step-task","errorCode":null,"errorMessage":"Cannot update task '{task.Id}' because its parent step '{task.StepId}' is already complete.","messagePattern":"Cannot update task '(.+?)' because its parent step '(.+?)' is already complete\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting/Pipelines/PipelineActivityReporter.cs","lineNumber":153,"sourceCode":"            Type = PublishingActivityTypes.Step,\n            Data = CreateStepActivityData(step, completionText, completionState, enableMarkdown)\n        };\n\n        await ActivityItemUpdated.Writer.WriteAsync(state, cancellationToken).ConfigureAwait(false);\n    }\n\n    public async Task UpdateTaskAsync(ReportingTask task, string statusText, bool enableMarkdown, CancellationToken cancellationToken)\n    {\n        if (!_steps.TryGetValue(task.StepId, out var parentStep))\n        {\n            throw new InvalidOperationException($\"Parent step with ID '{task.StepId}' does not exist.\");\n        }\n\n        lock (parentStep)\n        {\n            if (parentStep.CompletionState != CompletionState.InProgress)\n            {\n                throw new InvalidOperationException($\"Cannot update task '{task.Id}' because its parent step '{task.StepId}' is already complete.\");\n            }\n\n            task.StatusText = statusText;\n        }\n\n        var state = new PublishingActivity\n        {\n            Type = PublishingActivityTypes.Task,\n            Data = new PublishingActivityData\n            {\n                Id = task.Id,\n                StatusText = statusText,\n                CompletionState = ToBackchannelCompletionState(CompletionState.InProgress),\n                StepId = task.StepId,\n                EnableMarkdown = enableMarkdown\n            }\n        };\n","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting/Pipelines/PipelineActivityReporter.cs#L135-L171","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n_ = Task.Run(async () => { while (true) await reporter.UpdateTaskAsync(task, progress, false); });\n// after\nwhile (task.CompletionState == CompletionState.InProgress)\n    await reporter.UpdateTaskAsync(task, progress, false);","handlingStrategy":"try-catch","validationCode":"if (parentStep?.CompletionState != CompletionState.InProgress) return;","typeGuard":"bool CanUpdateTask(ReportingTask task) => task.CompletionState == CompletionState.InProgress;","tryCatchPattern":"try { await reporter.UpdateTaskAsync(task, text, false); } catch (InvalidOperationException ex) when (ex.Message.Contains(\"already complete\")) { logger.LogDebug(\"Step already complete; final status kept.\"); }","preventionTips":["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"],"tags":["reporting","lifecycle","race-condition"],"backgroundTag":"invalid-state-transition","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T09:17:21.228Z"}