App-vNext/Polly · error · InvalidOperationException
You have executed the generic .Execute<TResult> method on a
Error message
You have executed the generic .Execute<TResult> method on a non-generic FallbackPolicy. A non-generic FallbackPolicy only defines a fallback action which returns void; it can never return a substitute TResult value. To use FallbackPolicy to provide fallback TResult values you must define a generic fallback policy FallbackPolicy<TResult>. For example, define the policy as Policy<TResult>.Handle<Whatever>.Fallback<TResult>(/* some TResult value or Func<..., TResult> */);
What it means
The synchronous sibling of the async case: calling Execute<TResult> on a non-generic FallbackPolicy throws InvalidOperationException because a void fallback action cannot produce a substitute TResult. Build a generic FallbackPolicy<TResult> via Policy<TResult>.Handle<...>().Fallback<TResult>(...) when you need to return a fallback value.
Source
Thrown at src/Polly/Fallback/FallbackPolicy.cs:44
(ctx, token) =>
{
action(ctx, token);
return EmptyStruct.Instance;
},
context,
ExceptionPredicates,
ResultPredicates<EmptyStruct>.None,
(outcome, ctx) => _onFallback(outcome.Exception, ctx),
(outcome, ctx, ct) =>
{
_fallbackAction(outcome.Exception, ctx, ct);
return EmptyStruct.Instance;
},
cancellationToken);
/// <inheritdoc/>
protected override TResult Implementation<TResult>(Func<Context, CancellationToken, TResult> action, Context context, CancellationToken cancellationToken) =>
throw new InvalidOperationException($"You have executed the generic .Execute<{nameof(TResult)}> method on a non-generic {nameof(FallbackPolicy)}. " +
$"A non-generic {nameof(FallbackPolicy)} only defines a fallback action which returns void; it can never return a substitute {nameof(TResult)} value. " +
$"To use {nameof(FallbackPolicy)} to provide fallback {nameof(TResult)} values you must define a generic fallback policy {nameof(FallbackPolicy)}<{nameof(TResult)}>. " +
$"For example, define the policy as Policy<{nameof(TResult)}>.Handle<Whatever>.Fallback<{nameof(TResult)}>(/* some {nameof(TResult)} value or Func<..., {nameof(TResult)}> */);");
}
/// <summary>
/// A fallback policy that can be applied to delegates returning a value of type <typeparamref name="TResult"/>.
/// </summary>
/// <typeparam name="TResult">The type of the result.</typeparam>
public class FallbackPolicy<TResult> : Policy<TResult>, IFallbackPolicy<TResult>
{
private readonly Action<DelegateResult<TResult>, Context> _onFallback;
private readonly Func<DelegateResult<TResult>, Context, CancellationToken, TResult> _fallbackAction;
internal FallbackPolicy(
PolicyBuilder<TResult> policyBuilder,
Action<DelegateResult<TResult>, Context> onFallback,
Func<DelegateResult<TResult>, Context, CancellationToken, TResult> fallbackAction)View on GitHub (pinned to d0e46bdb1e)
Solutions
- Use Policy<TResult>.Handle<...>().Fallback<TResult>(fallbackValue/fallbackAction, onFallback) and call Execute (non-generic TResult is inferred).
- Keep non-generic FallbackPolicy paired with non-generic Execute only.
- Align the declared policy variable's generic-arity with the Execute<TResult> you intend to call.
Example fix
// before
var policy = Policy
.Handle<InvalidOperationException>()
.Fallback((ex, ctx, ct) => { /* void */ });
int v = policy.Execute<int>(() => Compute()); // throws
// after
var policy = Policy<int>
.Handle<InvalidOperationException>()
.Fallback(fallbackValue: 0, onFallback: outcome => { });
int v = policy.Execute(() => Compute()); Defensive patterns
Strategy: type-guard
Validate before calling
var policy = Policy<int>.Handle<InvalidOperationException>()
.Fallback(fallbackValue: 0, onFallback: _ => { });
int v = policy.Execute(() => Compute()); Type guard
static bool IsResultFallbackPolicy(object p) => p is IFallbackPolicy<int>;
Try / catch
try { return policy.Execute<TResult>(action); } catch (InvalidOperationException ex) when (ex.Message.Contains("non-generic FallbackPolicy")) { /* fix arity */ throw; } Prevention
- Match the Execute<TResult> arity with a Policy<TResult>-based Fallback.
- Avoid sharing a non-generic Policy field across value-returning call sites.
- Add a compile-time unit test exercising the value-returning Execute path.
When it happens
Trigger: Policy.Handle<X>().Fallback(...) (non-generic, sync) followed by policy.Execute<TResult>(...).
Common situations: Migrating a void synchronous fallback to a value-returning one without switching to Policy<TResult>; using a shared policy field declared as non-generic Policy for a result-returning call site.
Related errors
- You have executed the generic .Execute<TResult> method on a
- Value cannot be null. (Parameter 'fallbackAction')
- Value must be greater than zero.
- Value cannot be null. (Parameter 'onFallback')
- Value cannot be null. (Parameter 'action')
AI-assisted analysis of App-vNext/Polly@d0e46bdb1e (2026-08-13).
Data as JSON: /api/errors/5b705d7ab53d06e4.
Report an issue: GitHub.