{"record":{"id":"178cc7e12d254745","repo":"dotnet/reactive","slug":"the-scheduler-operation-has-already-been-awaited","errorCode":null,"errorMessage":"The scheduler operation has already been awaited.","messagePattern":"The scheduler operation has already been awaited\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Concurrency/SchedulerOperation.cs","lineNumber":98,"sourceCode":"        /// <summary>\n        /// Completes the scheduler operation, throwing an OperationCanceledException in case cancellation was requested.\n        /// </summary>\n        public void GetResult() => _cancellationToken.ThrowIfCancellationRequested();\n\n        /// <summary>\n        /// Registers the continuation with the scheduler operation.\n        /// </summary>\n        /// <param name=\"continuation\">Continuation to be run on the originating scheduler.</param>\n        public void OnCompleted(Action continuation)\n        {\n            if (continuation == null)\n            {\n                throw new ArgumentNullException(nameof(continuation));\n            }\n\n            if (_continuation != null)\n            {\n                throw new InvalidOperationException(Strings_Core.SCHEDULER_OPERATION_ALREADY_AWAITED);\n            }\n\n            if (_postBackToOriginalContext)\n            {\n                var ctx = SynchronizationContext.Current;\n                if (ctx != null)\n                {\n                    var original = continuation;\n                    continuation = () =>\n                    {\n                        //\n                        // No need for OperationStarted and OperationCompleted calls here;\n                        // this code is invoked through await support and will have a way\n                        // to observe its start/complete behavior, either through returned\n                        // Task objects or the async method builder's interaction with the\n                        // SynchronizationContext object.\n                        //\n                        // In general though, Rx doesn't play nicely with synchronization","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Concurrency/SchedulerOperation.cs#L80-L116","documentation":"A SchedulerOperation can only be awaited once: OnCompleted stores the continuation and throws InvalidOperationException ('The scheduler operation has already been awaited') on a second registration. This protects the single-continuation awaitable contract.","triggerScenarios":"Awaiting the same SchedulerOperation instance twice; calling OnCompleted again after a previous await completed or was cancelled; storing the operation and re-awaiting on retry logic.","commonSituations":"Retry loops that reuse the awaitable instead of obtaining a new operation; awaiting in both the original async method and a timeout/abandonment helper; caching the task-like object.","solutions":["Await each SchedulerOperation exactly once; create a new operation for each await","If retrying, re-issue the scheduled operation instead of re-awaiting the old one","Capture the result via Task-like semantics only once and share the resulting Task instead"],"exampleFix":"// before\nvar op = scheduler.ScheduleAsync(...);\nawait op;\nawait op; // second await throws\n// after\nvar op = scheduler.ScheduleAsync(...);\nawait op;\nvar op2 = scheduler.ScheduleAsync(...); // new operation for second await\nawait op2;","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await operation; }\ncatch (InvalidOperationException) { /* already awaited: treat as no-op */ }","preventionTips":["Await each SchedulerOperation exactly once","Store a Task/awaited result instead of the operation for reuse","In retry loops, create a fresh operation per attempt","Track awaited state if wrapping the operation in your own type"],"tags":["invalid-operation","async-await","scheduler","awaitable"],"backgroundTag":"invalid-state-transition","analyzedSha":"94b5d5ab912789f5abe9a72138a25bbd716fe59c","analyzedAt":"2026-09-15T02:26:24.759Z","contentChangedAt":"2026-09-15T02:26:24.759Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}