App-vNext/Polly · error · InvalidOperationException

No predicates were configured. There must be at least one pr

Error message

No predicates were configured. There must be at least one predicate added.

What it means

PredicateBuilder<TResult>.Build() throws InvalidOperationException when _predicates is empty. The builder is the fluent API for declaring which outcomes/exceptions a strategy handles; a strategy must handle at least one outcome, so an empty predicate set is rejected at Build() time rather than silently matching nothing.

Source

Thrown at src/Polly.Core/PredicateBuilder.TResult.cs:128

    {
        comparer ??= EqualityComparer<TResult>.Default;

        return HandleResult(r => comparer.Equals(r, result));
    }

    /// <summary>
    /// Builds the predicate.
    /// </summary>
    /// <returns>An instance of predicate delegate.</returns>
    /// <exception cref="InvalidOperationException">Thrown when no predicates were configured using this builder.</exception>
    /// <remarks>
    /// The returned predicate will return <see langword="true"/> if any of the configured predicates return <see langword="true"/>.
    /// Please be aware of the performance penalty if you register too many predicates with this builder. In such case, it's better to create your own predicate
    /// manually as a delegate.
    /// </remarks>
    public Predicate<Outcome<TResult>> Build() => _predicates.Count switch
    {
        0 => throw new InvalidOperationException("No predicates were configured. There must be at least one predicate added."),
        1 => _predicates[0],
        _ => CreatePredicate([.. _predicates]),
    };

    internal Func<TArgs, ValueTask<bool>> Build<TArgs>()
        where TArgs : IOutcomeArguments<TResult>
    {
        var predicate = Build();

        return args => new ValueTask<bool>(predicate(args.Outcome));
    }

    private static Predicate<Outcome<TResult>> CreatePredicate(Predicate<Outcome<TResult>>[] predicates) =>
        outcome =>
        {
            foreach (var predicate in predicates)
            {
                if (predicate(outcome))

View on GitHub (pinned to d0e46bdb1e)

Solutions

  1. Add at least one predicate via .Handle<ExceptionType>(), .HandleResult(predicate), or .Of<TResult>() before calling Build().
  2. Prefer the PredicateBuilder fluent chain inline at the options site so the empty case is visually obvious.
  3. If you genuinely want to handle nothing, do not add the strategy at all rather than passing an empty predicate.

Example fix

// before
var predicates = new PredicateBuilder<HttpResponseMessage>();
options.ShouldHandle = predicates.Build(); // throws

// after
var predicates = new PredicateBuilder<HttpResponseMessage>()
    .Handle<HttpRequestException>()
    .HandleResult(r => r.StatusCode >= System.Net.HttpStatusCode.InternalServerError);
options.ShouldHandle = predicates.Build();
Defensive patterns

Strategy: validation

Validate before calling

// Guard the builder before Build():
if (builder == null || /* no Handle added */) {
    throw new InvalidOperationException("Add at least one predicate before building.");
}
// Or check the strategy: most *StrategyOptions have a non-null default ShouldHandle, so
// only call builder.Build() when you have explicitly added predicates.

Try / catch

try { var predicate = builder.Build(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("No predicates")) {
    // add a default predicate and rebuild, or skip the strategy
}

Prevention

When it happens

Trigger: Constructing a PredicateBuilder, never calling .Handle<TException>(), .HandleResult(...), .Of<T>() etc., and then assigning builder.Build() to RetryStrategyOptions.ShouldHandle, then Build()ing the pipeline.

Common situations: Building predicates conditionally where every branch is skipped; refactoring that deletes the only .Handle call; copy-pasting a builder setup and forgetting the predicate lines.

Related errors


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