dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'context')
Error message
Value cannot be null. (Parameter 'context')
What it means
The ContextDisposable constructor throws ArgumentNullException when the context argument is null. ContextDisposable captures a SynchronizationContext on which Dispose will later be posted, so a null context would make the disposal behavior undefined. The constructor uses the ?? throw idiom to fail fast.
Solutions
- Pass an explicit context (e.g. a captured UI SynchronizationContext) instead of relying on SynchronizationContext.Current.
- Guard before constructing: var ctx = SynchronizationContext.Current ?? new SynchronizationContext();
- If no context is needed, use a plain disposable (Disposable.Create) instead of ContextDisposable.
Example fix
// before var d = new ContextDisposable(SynchronizationContext.Current, resource); // after var ctx = SynchronizationContext.Current ?? new SynchronizationContext(); var d = new ContextDisposable(ctx, resource);
Defensive patterns
Strategy: validation
Validate before calling
var ctx = SynchronizationContext.Current ?? new SynchronizationContext(); var d = new ContextDisposable(ctx, resource);
Type guard
ContextDisposable TryCreate(SynchronizationContext ctx, IDisposable d) => ctx == null || d == null ? null : new ContextDisposable(ctx, d);
Try / catch
try { var d = new ContextDisposable(context, resource); } catch (ArgumentNullException ex) when (ex.ParamName == "context") { /* fall back to plain Disposable.Create */ } Prevention
- Never rely on SynchronizationContext.Current being non-null on threadpool/console threads
- Capture the UI context explicitly at app startup
- Use ContextDisposable only when a real sync context exists
When it happens
Trigger: new ContextDisposable(null, someDisposable), typically when SynchronizationContext.Current is null (e.g. on a threadpool/console thread) and was passed through blindly.
Common situations: Capturing SynchronizationContext.Current in library code running without an installed context (console apps, ASP.NET Core, threadpool work items); UI code that lost its dispatcher context.
Related errors
- Value cannot be null. (Parameter 'onNextAsync')
- Value cannot be null. (Parameter 'onErrorAsync')
- Value cannot be null. (Parameter 'onCompletedAsync')
- Value cannot be null. (Parameter 'disposable')
- Value cannot be null. (Parameter 'second')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/fb232f4a7651bc59.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Disposables/ContextDisposable.cs:25
namespace System.Reactive.Disposables
{
/// <summary>
/// Represents a disposable resource whose disposal invocation will be posted to the specified <seealso cref="SynchronizationContext"/>.
/// </summary>
public sealed class ContextDisposable : ICancelable
{
private volatile IDisposable _disposable;
/// <summary>
/// Initializes a new instance of the <see cref="ContextDisposable"/> class that uses the specified <see cref="SynchronizationContext"/> on which to dispose the specified disposable resource.
/// </summary>
/// <param name="context">Context to perform disposal on.</param>
/// <param name="disposable">Disposable whose Dispose operation to run on the given synchronization context.</param>
/// <exception cref="ArgumentNullException"><paramref name="context"/> or <paramref name="disposable"/> is null.</exception>
public ContextDisposable(SynchronizationContext context, IDisposable disposable)
{
Context = context ?? throw new ArgumentNullException(nameof(context));
_disposable = disposable ?? throw new ArgumentNullException(nameof(disposable));
}
/// <summary>
/// Gets the provided <see cref="SynchronizationContext"/>.
/// </summary>
public SynchronizationContext Context { get; }
/// <summary>
/// Gets a value that indicates whether the object is disposed.
/// </summary>
public bool IsDisposed => _disposable == BooleanDisposable.True;
/// <summary>
/// Disposes the underlying disposable on the provided <see cref="SynchronizationContext"/>.
/// </summary>
public void Dispose()
{View on GitHub (pinned to 94b5d5ab91)