dotnet/reactive · error · InvalidOperationException

Strings_Core.COMPLETED_NO_VALUE

Error message

Strings_Core.COMPLETED_NO_VALUE

What it means

OnCompletedNotification<T>.Value throws InvalidOperationException with Strings_Core.COMPLETED_NO_VALUE. An OnCompleted notification carries no value, so reading .Value is semantically invalid; Rx models this as an InvalidOperationException rather than returning default(T) to avoid silently propagating a meaningless value.

Solutions

  1. Check notification.Kind == NotificationKind.OnCompleted (or OnError) before reading Value.
  2. Pattern-match on the concrete type (OnNextNotification<T> vs OnCompletedNotification<T> / OnErrorNotification<T>).
  3. Use Accept with handlers instead of touching Value directly.

Example fix

// before
var value = notification.Value;
// after
var value = notification.Kind == NotificationKind.OnNext ? notification.Value : default;
Defensive patterns

Strategy: type-guard

Validate before calling

if (notification.Kind != NotificationKind.OnNext) throw new InvalidOperationException("Value is only available on OnNext notifications");
var value = notification.Value;

Type guard

static bool TryGetValue<T>(Notification<T> n, out T? value) { value = default; return n.Kind == NotificationKind.OnNext && (value = n.Value) is not null || n.Kind == NotificationKind.OnNext; } // safer: pattern-match concrete types

Try / catch

try { value = notification.Value; } catch (InvalidOperationException ex) when (ex.Message.Contains("COMPLETED") || ex.Message.Contains("completed")) { value = default; }

Prevention

When it happens

Trigger: Accessing the Value property of a Notification<T> whose Kind is OnCompleted — typically without first checking notification.Kind or pattern-matching on the concrete notification type.

Common situations: Code that receives materialized notifications from a sequence, logs or serializes all notifications uniformly, and reads Value unconditionally; or unit-test assertions that inspect Value for every notification.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Notification.cs:403

        internal sealed class OnCompletedNotification : Notification<T>
        {
            /// <summary>
            /// Complete notifications are stateless thus only one instance
            /// can ever exist per type.
            /// </summary>
            internal static readonly Notification<T> Instance = new OnCompletedNotification();

            /// <summary>
            /// Constructs a notification of the end of a sequence.
            /// </summary>
            private OnCompletedNotification()
            {
            }

            /// <summary>
            /// Throws an <see cref="InvalidOperationException"/>.
            /// </summary>
            public override T Value { get { throw new InvalidOperationException(Strings_Core.COMPLETED_NO_VALUE); } }

            /// <summary>
            /// Returns <c>null</c>.
            /// </summary>
            public override Exception? Exception => null;

            /// <summary>
            /// Returns <c>false</c>.
            /// </summary>
            public override bool HasValue => false;

            /// <summary>
            /// Returns <see cref="NotificationKind.OnCompleted"/>.
            /// </summary>
            public override NotificationKind Kind => NotificationKind.OnCompleted;

            /// <summary>
            /// Returns the hash code for this instance.

View on GitHub (pinned to 94b5d5ab91)