dotnet/reactive · error · ArgumentNullException
nameof(finallyAction)
Error message
nameof(finallyAction)
What it means
This is an ArgumentNullException thrown by the Finally operator when the finallyAction delegate is null. The Finally operator requires an Action to invoke after the source sequence terminates (normally, with error, or on disposal), so it validates the delegate up front before building the pipeline. Passing null means the operator could not guarantee its post-termination hook.
Solutions
- Ensure a non-null Action is passed; if no work is needed on termination, omit the Finally call entirely rather than passing null
- If the delegate is conditional, coalesce to a no-op: source.Finally(() => { })
- Check the variable holding the callback for initialization/null propagation issues before calling Finally
Example fix
// before
IAsyncObservable<int> res = source.Finally(cleanupAction); // cleanupAction is null
// after
if (cleanupAction == null)
return source; // nothing to do on termination
IAsyncObservable<int> res = source.Finally(cleanupAction); Defensive patterns
Strategy: validation
Validate before calling
if (source == null) throw new ArgumentNullException(nameof(source)); if (finallyAction == null) throw new ArgumentNullException(nameof(finallyAction)); var result = source.Finally(finallyAction);
Type guard
bool IsValidFinally(Action? a) => a is not null;
Try / catch
try
{
var result = source.Finally(finallyAction);
}
catch (ArgumentNullException ex) when (ex.ParamName == nameof(finallyAction))
{
result = source; // skip the termination hook
} Prevention
- Never pass null for optional cleanup — omit the Finally operator instead
- Default optional delegates to a no-op lambda: () => { }
- Validate delegates at the pipeline's entry point, not inside operators
When it happens
Trigger: Calling source.Finally(null) — the Action overload — on an IAsyncObservable<TSource>. Typically caused by a variable holding the callback being null (optional callback not supplied), a factory method returning null, or a refactor that renamed a method and left a null delegate.
Common situations: Conditional instrumentation/teardown code where the cleanup action is only assigned in some code paths; DI-registered callback services that are null in test environments; passing the result of a method that returns null instead of a no-op.
Related errors
- nameof(source)
- nameof(predicate)
- ArgumentNullException
- ArgumentNullException
- Value cannot be null. (Parameter 'onCompletedAsync')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/87083dc50f3efa49.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Finally.cs:17
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT License.
// See the LICENSE file in the project root for more information.
using System.Reactive.Disposables;
using System.Threading.Tasks;
namespace System.Reactive.Linq
{
public partial class AsyncObservable
{
public static IAsyncObservable<TSource> Finally<TSource>(this IAsyncObservable<TSource> source, Action finallyAction)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (finallyAction == null)
throw new ArgumentNullException(nameof(finallyAction));
return Create(
source,
finallyAction,
static async (source, finallyAction, observer) =>
{
var subscription = await source.SubscribeSafeAsync(observer).ConfigureAwait(false);
return AsyncDisposable.Create(async () =>
{
try
{
await subscription.DisposeAsync().ConfigureAwait(false);
}
finally
{
finallyAction();
}View on GitHub (pinned to 94b5d5ab91)