{"record":{"id":"f9715c329ac18c0c","repo":"stride3d/stride","slug":"microthread-was-already-started-before","errorCode":null,"errorMessage":"MicroThread was already started before.","messagePattern":"MicroThread was already started before\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core.MicroThreading/MicroThread.cs","lineNumber":166,"sourceCode":"        throw new NotImplementedException();\n    }\n\n    public void Remove()\n    {\n        throw new NotImplementedException();\n    }\n\n    /// <summary>\n    /// Starts this <see cref=\"MicroThread\"/> with the specified function.\n    /// </summary>\n    /// <param name=\"microThreadFunction\">The micro thread function.</param>\n    /// <param name=\"scheduleMode\">The schedule mode.</param>\n    /// <exception cref=\"System.InvalidOperationException\">MicroThread was already started before.</exception>\n    public void Start(Func<Task> microThreadFunction, ScheduleMode scheduleMode = ScheduleMode.Last)\n    {\n        // TODO: Interlocked compare exchange?\n        if (Interlocked.CompareExchange(ref state, (int)MicroThreadState.Starting, (int)MicroThreadState.None) != (int)MicroThreadState.None)\n            throw new InvalidOperationException(\"MicroThread was already started before.\");\n\n        Func<Task> wrappedMicroThreadFunction = async () =>\n        {\n            try\n            {\n                State = MicroThreadState.Running;\n\n                await microThreadFunction();\n\n                if (State != MicroThreadState.Running)\n                    throw new InvalidOperationException(\"MicroThread completed in an invalid state.\");\n                State = MicroThreadState.Completed;\n            }\n            catch (OperationCanceledException e)\n            {\n                // Exit gracefully on cancellation exceptions\n                SetException(e);\n            }","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core.MicroThreading/MicroThread.cs#L148-L184","documentation":"MicroThread.Start transitions the thread state from None to Starting atomically. If the instance was already started (state != None), it throws InvalidOperationException, since a micro-thread's lifetime is single-use; create a new instance to run again.","triggerScenarios":"Calling Start() twice on the same MicroThread instance, or calling Start after Schedule was invoked.","commonSituations":"Restarting a failed/completed micro-thread by calling Start again in a game update loop; reusing cached MicroThread objects across levels or asset reloads; callers like ScheduleBuildStep/Add that invoke Start on shared instances.","solutions":["Create a new MicroThread instance for each run instead of restarting","Track whether the thread was started (check State before Start)","Use Scheduler context (e.g. microThread.Tasks / Spawn helpers) which allocate fresh instances"],"exampleFix":"// before\nif (!myThread.State.HasFlag(MicroThreadState.Running)) myThread.Start(work); // reuses old instance\n// after\nvar myThread = Scheduler.CreateMicroThread();\nmyThread.Start(work);","handlingStrategy":"validation","validationCode":"if (microThread.State != MicroThreadState.None) microThread = scheduler.CreateMicroThread();","typeGuard":null,"tryCatchPattern":"try { microThread.Start(work); }\ncatch (InvalidOperationException) { microThread = scheduler.CreateMicroThread(); microThread.Start(work); }","preventionTips":["Treat MicroThread instances as single-use","Check State before Start","Allocate fresh instances per run/level"],"tags":["csharp","microthreading","invalid-operation","stride"],"backgroundTag":"invalid-state-transition","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}