{"record":{"id":"a1afb3a9fc38758b","repo":"spectreconsole/spectre.console","slug":"stopped-tasks-cannot-be-restarted","errorCode":null,"errorMessage":"Stopped tasks cannot be restarted","messagePattern":"Stopped tasks cannot be restarted","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Spectre.Console/Live/Progress/ProgressTask.cs","lineNumber":159,"sourceCode":"        {\n            throw new ArgumentException(\"Task name cannot be empty\", nameof(description));\n        }\n\n        Id = id;\n        State = new ProgressTaskState();\n        StartTime = autoStart ? _timeProvider.GetLocalNow().LocalDateTime : null;\n    }\n\n    /// <summary>\n    /// Starts the task.\n    /// </summary>\n    public void StartTask()\n    {\n        lock (_lock)\n        {\n            if (StopTime != null)\n            {\n                throw new InvalidOperationException(\"Stopped tasks cannot be restarted\");\n            }\n\n            StartTime = _timeProvider.GetLocalNow().LocalDateTime;\n            StopTime = null;\n        }\n    }\n\n    /// <summary>\n    /// Stops and marks the task as finished.\n    /// </summary>\n    public void StopTask()\n    {\n        lock (_lock)\n        {\n            var now = _timeProvider.GetLocalNow().LocalDateTime;\n            StartTime ??= now;\n            StopTime = now;\n        }","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/spectreconsole/spectre.console/blob/0acc92fada6c42f13984e79c2b5f3d993bdfb099/src/Spectre.Console/Live/Progress/ProgressTask.cs#L141-L177","documentation":"Thrown by ProgressTask.StartTask() when StopTime is already set (the task has been stopped/finished). ProgressTask follows a one-way lifecycle: created → started → stopped. Once StopTask() sets StopTime, the task is permanently finished and StartTask() refuses to reset it. This InvalidOperationException prevents confusing speed/duration calculations and state corruption.","triggerScenarios":"Calling task.StopTask() followed by task.StartTask() on the same ProgressTask instance. Also triggered by code that reuses ProgressTask objects in a loop or pool. Calling StartTask on an auto-started task that was already stopped by the framework.","commonSituations":"Loop that reuses a ProgressTask for multiple operations; retry logic that tries to restart a stopped task; event-driven code where StopTask and StartTask can race.","solutions":["Create a new ProgressTask for each operation rather than restarting a stopped one.","Check task.IsFinished before calling StartTask (IsFinished is true when StopTime is set).","Track task lifecycle state in your code to avoid calling StartTask after StopTask."],"exampleFix":"// before\ntask.StopTask();\n// ... later\ntask.StartTask(); // throws\n\n// after\ntask.StopTask();\ntask = ctx.AddTask(\"New operation\"); // fresh task","handlingStrategy":"validation","validationCode":"// Check lifecycle before restarting\nif (task.IsFinished)\n{\n    // Create a new task instead of restarting\n    task = ctx.AddTask(description);\n}\nelse\n{\n    task.StartTask();\n}","typeGuard":"static bool CanRestart(ProgressTask task) => !task.IsFinished;","tryCatchPattern":"try\n{\n    task.StartTask();\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"cannot be restarted\"))\n{\n    // Create a fresh task\n    task = ctx.AddTask(task.Description);\n}","preventionTips":["Never reuse stopped ProgressTask instances — create new ones for each operation.","Check IsFinished before calling StartTask.","Track task lifecycle in your orchestration code.","Design progress loops that allocate fresh tasks per unit of work."],"tags":["invalidoperationexception","progress","progress-task","lifecycle","state"],"backgroundTag":null,"analyzedSha":"0acc92fada6c42f13984e79c2b5f3d993bdfb099","analyzedAt":"2026-08-13T18:27:21.983Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}