dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'finallyAction')

Error message

Value cannot be null. (Parameter 'finallyAction')

What it means

Thrown by the generated AsyncQueryableEx.Finally extension when finallyAction is null. The action is embedded into the expression tree as Expression.Constant(finallyAction, typeof(Action)), which cannot be null, so the library validates it up front.

Solutions

  1. Pass a real action, e.g. q.Finally(() => logger.Flush())
  2. If cleanup is optional, skip the Finally call when the action is null instead of passing null
  3. Default the action to a no-op: () => {}
  4. Check the DI/config registration that should provide the callback

Example fix

// before
Action cleanup = GetCleanupHook(); // null when not configured
var q = source.Finally(cleanup);
// after
var cleanup = GetCleanupHook();
var q = cleanup != null ? source.Finally(cleanup) : source;
Defensive patterns

Strategy: validation

Validate before calling

if (finallyAction is null) throw new ArgumentNullException(nameof(finallyAction));

Type guard

bool HasCleanup(Action? a) => a is not null;

Try / catch

try { query = source.Finally(action); }
catch (ArgumentNullException ex) when (ex.ParamName == "finallyAction") { throw new InvalidOperationException("Finally cleanup action was null", ex); }

Prevention

When it happens

Trigger: Calling Finally(source, null) or passing an Action field/delegate variable that was never assigned.

Common situations: Optional cleanup hooks configured externally where the hook was not registered; delegates wired via events or DI that remain null in some environments.

Related errors


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

Appendix: source

Thrown at Ix.NET/Source/System.Interactive.Async.Providers/System/Linq/AsyncQueryableEx.Generated.cs:1144

                throw new ArgumentNullException(nameof(source));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));

            return source.Provider.CreateQuery<TSource>(Expression.Call(Expand__TSource__2__2(typeof(TSource)), source.Expression, selector));
        }

        private static MethodInfo? s_Finally__TSource__2__0;
        
        private static MethodInfo Finally__TSource__2__0(Type TSource) =>
            (s_Finally__TSource__2__0 ??
            (s_Finally__TSource__2__0 = new Func<IAsyncQueryable<object>, Action, IAsyncQueryable<object>>(Finally<object>).GetMethodInfo()!.GetGenericMethodDefinition())).MakeGenericMethod(TSource);

        public static IAsyncQueryable<TSource> Finally<TSource>(this IAsyncQueryable<TSource> source, Action finallyAction)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (finallyAction == null)
                throw new ArgumentNullException(nameof(finallyAction));

            return source.Provider.CreateQuery<TSource>(Expression.Call(Finally__TSource__2__0(typeof(TSource)), source.Expression, Expression.Constant(finallyAction, typeof(Action))));
        }

        private static MethodInfo? s_Finally__TSource__2__1;
        
        private static MethodInfo Finally__TSource__2__1(Type TSource) =>
            (s_Finally__TSource__2__1 ??
            (s_Finally__TSource__2__1 = new Func<IAsyncQueryable<object>, Expression<Func<Task>>, IAsyncQueryable<object>>(Finally<object>).GetMethodInfo()!.GetGenericMethodDefinition())).MakeGenericMethod(TSource);

        public static IAsyncQueryable<TSource> Finally<TSource>(this IAsyncQueryable<TSource> source, Expression<Func<Task>> finallyAction)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (finallyAction == null)
                throw new ArgumentNullException(nameof(finallyAction));

            return source.Provider.CreateQuery<TSource>(Expression.Call(Finally__TSource__2__1(typeof(TSource)), source.Expression, finallyAction));

View on GitHub (pinned to 94b5d5ab91)