{"record":{"id":"a66c953f4cd9fafc","repo":"dotnet/reactive","slug":"the-asynchronous-operation-completed-unexpectedly","errorCode":null,"errorMessage":"The asynchronous operation completed unexpectedly.","messagePattern":"The asynchronous operation completed unexpectedly\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Platforms/WinRT/Foundation/AsyncInfoToObservableBridge.cs","lineNumber":64,"sourceCode":"            switch (status)\n            {\n                case AsyncStatus.Error:\n                    error = info.ErrorCode ?? throw new InvalidOperationException(\"The asynchronous operation failed with a null error code.\");\n                    break;\n                case AsyncStatus.Canceled:\n                    error = new OperationCanceledException();\n                    break;\n                case AsyncStatus.Completed:\n                    if (_getResult != null)\n                    {\n                        result = _getResult(info);\n                    }\n\n                    break;\n                default:\n                    if (!initial)\n                    {\n                        throw new InvalidOperationException(\"The asynchronous operation completed unexpectedly.\");\n                    }\n\n                    _onCompleted(info, (iai, s) => Done(iai, s, false));\n                    return;\n            }\n\n            //\n            // Close as early as possible, before running continuations which could fail. In case of\n            // failure above, we don't close out the object in order to allow for debugging of the\n            // rogue implementation without losing state prematurely. Notice _getResult is merely\n            // an indirect call to the appropriate GetResults method, which is not supposed to throw.\n            // Instead, an Error status should be returned.\n            //\n            info.Close();\n\n            //\n            // Now we run the continuations, which could take a long time. Failure here is catastrophic\n            // and under control of the upstream subscriber.","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Platforms/WinRT/Foundation/AsyncInfoToObservableBridge.cs#L46-L82","documentation":"In the bridge's Done callback, this InvalidOperationException is thrown when a continuation callback observes the IAsyncInfo in a status other than Error, Canceled, or Completed after the initial phase — i.e. the operation finished with an unrecognized/invalid state. It signals a contract violation by the underlying IAsyncInfo implementation.","triggerScenarios":"A resumption of the Done callback (initial=false) where the IAsyncInfo status is not one of the three valid terminal statuses — typically a rogue implementation whose Status getter returns an unexpected value after firing the completion event.","commonSituations":"Buggy custom WinRT async implementations, incorrect manual IAsyncInfo implementations in C++/WinRT or projections, or state races in non-conformant async objects.","solutions":["Fix the IAsyncInfo implementation so its Status only ever reports Error, Canceled, or Completed","Wrap the observable subscription in try-catch handling InvalidOperationException","Report the invalid status transitions to the vendor of the async component"],"exampleFix":"// before: rogue implementation returns default status after completion\n// after: guarantee terminal status\nStatus => _completed ? (_canceled ? AsyncStatus.Canceled : _exception != null ? AsyncStatus.Error : AsyncStatus.Completed) : AsyncStatus.Started","handlingStrategy":"try-catch","validationCode":"var s = asyncInfo.Status; if (s != AsyncStatus.Started && s != AsyncStatus.Error && s != AsyncStatus.Canceled && s != AsyncStatus.Completed) throw new InvalidOperationException($\"Invalid async status: {s}\");","typeGuard":"static bool HasValidTerminalStatus(AsyncStatus s) => s == AsyncStatus.Error || s == AsyncStatus.Canceled || s == AsyncStatus.Completed;","tryCatchPattern":"try { observable.ToTask(); } catch (InvalidOperationException ex) when (ex.Message == \"The asynchronous operation completed unexpectedly.\") { /* invalid state */ }","preventionTips":["Prefer standard async primitives (Task.ToObservable, AsyncInfo.Run) over custom IAsyncInfo","Ensure completion events fire only in terminal states","Add state-machine unit tests for custom async objects"],"tags":["winrt","async","invalid-state","interop"],"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-15T23:17:13.987Z"}