{"record":{"id":"84fc966b92e6486d","repo":"App-vNext/Polly","slug":"value-cannot-be-null-84fc96","errorCode":null,"errorMessage":"Value cannot be null.","messagePattern":"Value cannot be null\\.","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"src/Polly/Retry/AsyncRetryPolicy.cs","lineNumber":38,"sourceCode":"    {\n        _permittedRetryCount = permittedRetryCount;\n        _sleepDurationsEnumerable = sleepDurationsEnumerable;\n        _sleepDurationProvider = sleepDurationProvider;\n        _onRetryAsync = onRetryAsync;\n    }\n\n    /// <inheritdoc/>\n    [DebuggerStepThrough]\n\n    protected override Task<TResult> ImplementationAsync<TResult>(\n        Func<Context, CancellationToken, Task<TResult>> action,\n        Context context,\n        CancellationToken cancellationToken,\n        bool continueOnCapturedContext)\n    {\n        if (action is null)\n        {\n            throw new ArgumentNullException(nameof(action));\n        }\n\n        var sleepDurationProvider = _sleepDurationProvider != null\n            ? (retryCount, outcome, ctx) => _sleepDurationProvider(retryCount, outcome.Exception, ctx)\n            : (Func<int, DelegateResult<TResult>, Context, TimeSpan>)null;\n\n        return AsyncRetryEngine.ImplementationAsync(\n            action,\n            context,\n            ExceptionPredicates,\n            ResultPredicates<TResult>.None,\n            (outcome, timespan, retryCount, ctx) => _onRetryAsync(outcome.Exception, timespan, retryCount, ctx),\n            cancellationToken,\n            _permittedRetryCount,\n            _sleepDurationsEnumerable,\n            sleepDurationProvider,\n            continueOnCapturedContext);\n    }","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/App-vNext/Polly/blob/d0e46bdb1ee11ea50d0e4b6846d2633d6bc09bac/src/Polly/Retry/AsyncRetryPolicy.cs#L20-L56","documentation":"Thrown by AsyncRetryPolicy.ImplementationAsync<TResult> (the generic, exception-predicate-based legacy retry policy) when the action delegate is null. The retry engine needs a delegate to invoke on each attempt.","triggerScenarios":"Calling ExecuteAsync with a null action on an AsyncRetryPolicy built via the legacy RetryAsync exception-based syntax. The protected ImplementationAsync is reached through the base ExecuteAsync path.","commonSituations":"Passing a method-group that resolved to null; an action selected conditionally that stayed null; refactor that dropped the delegate argument.","solutions":["Pass a non-null Func<Context, CancellationToken, Task<TResult>>.","Verify the action variable is assigned before ExecuteAsync.","Use a no-op delegate returning default(TResult) if a placeholder is needed."],"exampleFix":"// before\nawait policy.ExecuteAsync(null, context, ct);\n// after\nawait policy.ExecuteAsync(_ => Task.FromResult(result), context, ct);","handlingStrategy":"validation","validationCode":"if (action is null) throw new ArgumentException(\"action must be set before executing the retry policy.\");\nawait policy.ExecuteAsync(action, context, cancellationToken);","typeGuard":"static bool IsActionSet<TResult>(Func<Context, CancellationToken, Task<TResult>> action) => action is not null;","tryCatchPattern":null,"preventionTips":["Pass a verified non-null delegate to ExecuteAsync.","Avoid conditional action assignment without a fallback.","Enable nullable reference types to flag null delegates at compile time."],"tags":["retry","argumentnull","async","delegate","legacy"],"backgroundTag":null,"analyzedSha":"d0e46bdb1ee11ea50d0e4b6846d2633d6bc09bac","analyzedAt":"2026-08-13T16:36:01.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}