{"record":{"id":"10175d3f49f327b4","repo":"stride3d/stride","slug":"microthread-is-already-completed-but-still-posting","errorCode":null,"errorMessage":"MicroThread is already completed but still posting continuations.","messagePattern":"MicroThread is already completed but still posting continuations\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core.MicroThreading/MicroThreadSynchronizationContext.cs","lineNumber":35,"sourceCode":"        return this;\n    }\n\n    public override void Post(SendOrPostCallback d, object? state)\n    {\n        // There is two case:\n        // 1/ We are either in normal MicroThread inside Scheduler.Step() (CurrentThread test),\n        // in which case we will directly execute the callback to avoid further processing from scheduler.\n        // Also, note that Wait() sends us event that are supposed to come back into scheduler.\n        // Note: As it will end up on the callstack, it might be better to Schedule it instead (to avoid overflow)?\n        // 2/ Otherwise, we just received an external task continuation (i.e. Task.Sleep()), or a microthread triggering another,\n        // so schedule it so that it comes back in our regular scheduler.\n        if (microThread.Scheduler.RunningMicroThread == microThread)\n        {\n            d(state);\n        }\n        else if (microThread.State == MicroThreadState.Completed)\n        {\n            throw new InvalidOperationException(\"MicroThread is already completed but still posting continuations.\");\n        }\n        else\n        {\n            microThread.ScheduleContinuation(microThread.ScheduleMode, d, state);\n        }\n    }\n\n    MicroThread IMicroThreadSynchronizationContext.MicroThread => microThread;\n}\n","sourceCodeStart":17,"sourceCodeEnd":45,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core.MicroThreading/MicroThreadSynchronizationContext.cs#L17-L45","documentation":"MicroThreadSynchronizationContext.Post schedules a continuation delegate on the micro-thread. If the target micro-thread is already Completed, there is nothing left to resume, so Post throws InvalidOperationException rather than silently dropping the continuation.","triggerScenarios":"Posting continuations (e.g. continuations captured by await/Task sources) to a micro-thread after its body finished — typically a TaskCompletionSource or SynchronizationContext captured earlier and completed after the thread finished.","commonSituations":"A TaskCompletionSource held by the micro-thread is SetResult'ed later by external code; events firing after the script completed; continuation stored and invoked by a timer or other micro-thread after completion.","solutions":["Check microThread.State == MicroThreadState.Completed before calling Post","Do not capture/use the micro-thread's SynchronizationContext after completion; marshal back through the scheduler with a fresh micro-thread if needed","Fix ownership so continuations are posted before the thread completes (complete sources within the body)"],"exampleFix":"// before\nsyncContext.Post(d, state); // d may run after thread completed\n// after\nif (microThread.State != MicroThreadState.Completed)\n    syncContext.Post(d, state);","handlingStrategy":"type-guard","validationCode":"if (microThread.State == MicroThreadState.Completed) return;","typeGuard":"bool canPost = microThread.State != MicroThreadState.Completed;","tryCatchPattern":"try { context.Post(d, state); }\ncatch (InvalidOperationException) { /* continuation target completed; drop or reschedule */ }","preventionTips":["Complete TaskCompletionSources inside the micro-thread body","Check State before Post","Don't hold the SynchronizationContext beyond thread lifetime"],"tags":["csharp","microthreading","synchronization-context","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"}