dotnet/reactive · error · ArgumentNullException
Thrown when finallyAction is null (ArgumentNullException…
Error message
Thrown when finallyAction is null (ArgumentNullException, param name: finallyAction)
What it means
Finally throws ArgumentNullException when finallyAction is null. The whole point of the operator is to invoke this action reliably, so a null action is invalid and rejected eagerly with paramName 'finallyAction'.
Solutions
- Provide a no-op () => {} when cleanup is genuinely optional.
- Ensure the cleanup delegate is registered/initialized before the call.
- Guard the delegate source with a default.
Example fix
// before
var seq = source.Finally(cleanup); // cleanup may be null
// after
var seq = source.Finally(cleanup ?? (() => { })); Defensive patterns
Strategy: validation
Validate before calling
if (finallyAction is null) throw new ArgumentNullException(nameof(finallyAction));
Finally(source, finallyAction ?? (() => { })); Type guard
bool HasAction(Action a) => a is not null;
Try / catch
try { var q = source.Finally(action); }
catch (ArgumentNullException ex) when (ex.ParamName == "finallyAction") { /* register or default the action */ } Prevention
- Register cleanup handlers during initialization, not lazily.
- Default optional actions to no-ops.
- Verify DI registrations for cleanup delegates.
- Avoid obj?.Handler forms that yield null delegates.
When it happens
Trigger: Calling Finally(source, null), e.g. a cleanup Action resolved from an optional member or DI registration that is missing.
Common situations: Optional cleanup callback not registered; passing a null delegate from configuration; refactoring removed the handler but kept the call.
Related errors
- Thrown when condition is null (ArgumentNullException, param…
- Thrown when onNext is null (ArgumentNullException, param…
- Thrown when resultSelector is null (ArgumentNullException…
- Thrown when selector is null (ArgumentNullException, param…
- Value cannot be null. (Parameter 'handler')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/df3ef33b51001f9a.
Report an issue: GitHub.
Appendix: source
Thrown at Ix.NET/Source/System.Interactive/System/Linq/Operators/Finally.cs:23
using System.Collections.Generic;
namespace System.Linq
{
public static partial class EnumerableEx
{
/// <summary>
/// Creates a sequence whose termination or disposal of an enumerator causes a finally action to be executed.
/// </summary>
/// <typeparam name="TSource">Source sequence element type.</typeparam>
/// <param name="source">Source sequence.</param>
/// <param name="finallyAction">Action to run upon termination of the sequence, or when an enumerator is disposed.</param>
/// <returns>Source sequence with guarantees on the invocation of the finally action.</returns>
public static IEnumerable<TSource> Finally<TSource>(this IEnumerable<TSource> source, Action finallyAction)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (finallyAction == null)
throw new ArgumentNullException(nameof(finallyAction));
return FinallyCore(source, finallyAction);
}
private static IEnumerable<TSource> FinallyCore<TSource>(IEnumerable<TSource> source, Action finallyAction)
{
try
{
foreach (var item in source)
{
yield return item;
}
}
finally
{
finallyAction();
}
}View on GitHub (pinned to 94b5d5ab91)