App-vNext/Polly · error · ArgumentNullException

Value cannot be null.

Error message

Value cannot be null.

What it means

Thrown as ArgumentNullException(nameof(action)) from BulkheadPolicy.Implementation<TResult> when the action delegate passed to the execution method is null. This is the non-generic BulkheadPolicy's override that delegates to BulkheadEngine. The guard at line 32–34 fires before any semaphore interaction, so no resources are consumed.

Source

Thrown at src/Polly/Bulkhead/BulkheadPolicy.cs:34

        int maxParallelization,
        int maxQueueingActions,
        Action<Context> onBulkheadRejected)
    {
        MaxQueueingActions = maxQueueingActions;
        _onBulkheadRejected = onBulkheadRejected;

        (_maxParallelizationSemaphore, _maxQueuedActionsSemaphore) = BulkheadSemaphoreFactory.CreateBulkheadSemaphores(maxParallelization, maxQueueingActions);
    }

    private int MaxQueueingActions { get; }

    /// <inheritdoc/>
    [DebuggerStepThrough]
    protected override TResult Implementation<TResult>(Func<Context, CancellationToken, TResult> action, Context context, CancellationToken cancellationToken)
    {
        if (action is null)
        {
            throw new ArgumentNullException(nameof(action));
        }

        return BulkheadEngine.Implementation(
            action,
            context,
            _onBulkheadRejected,
            _maxParallelizationSemaphore,
            _maxQueuedActionsSemaphore,
            cancellationToken);
    }

    /// <summary>
    /// Gets the number of slots currently available for executing actions through the bulkhead.
    /// </summary>
    public int BulkheadAvailableCount => _maxParallelizationSemaphore.CurrentCount;

    /// <summary>
    /// Gets the number of slots currently available for queuing actions for execution through the bulkhead.

View on GitHub (pinned to d0e46bdb1e)

Solutions

  1. Ensure the delegate passed to Execute/ExecuteAsync is non-null before calling
  2. If the action may legitimately be absent, guard the call site with a null check and skip execution
  3. Use nullable reference type annotations to catch null delegates at compile time

Example fix

// before
Action myAction = GetAction(); // may return null
policy.Execute(myAction); // ArgumentNullException

// after
Action myAction = GetAction();
if (myAction is not null)
{
    policy.Execute(myAction);
}
Defensive patterns

Strategy: validation

Validate before calling

if (action is null)
{
    throw new InvalidOperationException("Action must be provided before execution.");
}
policy.Execute(action);

Type guard

public static bool IsExecutableDelegate(Action action) => action is not null;

Try / catch

try
{
    policy.Execute(action);
}
catch (ArgumentNullException ex) when (ex.ParamName == "action")
{
    logger.LogError("Null action passed to bulkhead execution");
    throw;
}

Prevention

When it happens

Trigger: Calling policy.Execute(null) or policy.ExecuteAsync(null) on a non-generic BulkheadPolicy, or passing a lambda that resolves to null. The null check in Implementation<TResult> at BulkheadPolicy.cs:32–34 throws immediately.

Common situations: Passing a method reference that was never assigned (remains null). Conditional delegate construction where a branch returns null. Refactoring that accidentally removes the delegate body while keeping the call site.

Related errors


AI-assisted analysis of App-vNext/Polly@d0e46bdb1e (2026-08-13). Data as JSON: /api/errors/a8775d16e90a3db9. Report an issue: GitHub.