dotnet/reactive · error · InvalidOperationException

The asynchronous operation completed unexpectedly.

Error message

The asynchronous operation completed unexpectedly.

What it means

Done is first invoked with initial=true to hook completion callbacks. If it is called again (initial=false) and the status is neither Error, Canceled, nor Completed, the bridge has exhausted all known AsyncStatus values and considers the operation state invalid, throwing InvalidOperationException.

Solutions

  1. Ensure the IAsyncInfo implementation only returns valid AsyncStatus values (Started, Completed, Error, Canceled).
  2. Check for custom/mock IAsyncInfo implementations that set undefined status values.
  3. Catch InvalidOperationException around subscription and replace the source with a standard WinRT async operation.

Example fix

// before (broken mock)
public AsyncStatus Status => (AsyncStatus)99;
// after
public AsyncStatus Status => AsyncStatus.Completed;
Defensive patterns

Strategy: try-catch

Validate before calling

if ((int)info.Status is < 0 or > 3) throw new InvalidOperationException("Invalid AsyncStatus value");

Type guard

bool IsValidStatus(AsyncStatus s) => s is AsyncStatus.Started or AsyncStatus.Completed or AsyncStatus.Error or AsyncStatus.Canceled;

Try / catch

try { await obs; }
catch (InvalidOperationException ex) when (ex.Message.Contains("completed unexpectedly"))
{ /* replace source with conformant async operation */ }

Prevention

When it happens

Trigger: Re-entry of Done with initial=false while the underlying IAsyncInfo reports an unrecognized/undefined AsyncStatus value.

Common situations: Rogue IAsyncInfo implementations returning out-of-range status values; corrupted or mocked async objects in tests.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15). Data as JSON: /api/errors/e85f7e111c02358c. Report an issue: GitHub.

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive.WindowsRuntime/AsyncInfoToObservableBridge.cs:64

            switch (status)
            {
                case AsyncStatus.Error:
                    error = info.ErrorCode ?? throw new InvalidOperationException("The asynchronous operation failed with a null error code.");
                    break;
                case AsyncStatus.Canceled:
                    error = new OperationCanceledException();
                    break;
                case AsyncStatus.Completed:
                    if (_getResult != null)
                    {
                        result = _getResult(info);
                    }

                    break;
                default:
                    if (!initial)
                    {
                        throw new InvalidOperationException("The asynchronous operation completed unexpectedly.");
                    }

                    _onCompleted(info, (iai, s) => Done(iai, s, false));
                    return;
            }

            //
            // Close as early as possible, before running continuations which could fail. In case of
            // failure above, we don't close out the object in order to allow for debugging of the
            // rogue implementation without losing state prematurely. Notice _getResult is merely
            // an indirect call to the appropriate GetResults method, which is not supposed to throw.
            // Instead, an Error status should be returned.
            //
            info.Close();

            //
            // Now we run the continuations, which could take a long time. Failure here is catastrophic
            // and under control of the upstream subscriber.

View on GitHub (pinned to 94b5d5ab91)