App-vNext/Polly · error · ArgumentOutOfRangeException

The ttl for items to cache must be greater than zero.

Error message

The ttl for items to cache must be greater than zero.

What it means

Thrown by the legacy Polly v7 RelativeTtl constructor when the supplied TimeSpan is less than TimeSpan.Zero. RelativeTtl is a simple ITtlStrategy that caches items for a fixed duration; a negative duration is meaningless (and would be treated as 'already expired'), so Polly rejects it with ArgumentOutOfRangeException. Note TimeSpan.Zero is allowed but produces a TTL that expires immediately.

Source

Thrown at src/Polly/Caching/RelativeTtl.cs:19

#nullable enable
namespace Polly.Caching;

/// <summary>
/// Defines a ttl strategy which will cache items for the specified time.
/// </summary>
public class RelativeTtl : ITtlStrategy
{
    private readonly TimeSpan _ttl;

    /// <summary>
    /// Initializes a new instance of the <see cref="RelativeTtl"/> class.
    /// </summary>
    /// <param name="ttl">The timespan for which to consider the cache item valid.</param>
    public RelativeTtl(TimeSpan ttl)
    {
        if (ttl < TimeSpan.Zero)
        {
            throw new ArgumentOutOfRangeException(nameof(ttl), "The ttl for items to cache must be greater than zero.");
        }

        _ttl = ttl;
    }

    /// <summary>
    /// Gets a TTL for a cacheable item, given the current execution context.
    /// </summary>
    /// <param name="context">The execution context.</param>
    /// <param name="result">The execution result.</param>
    /// <returns>A <see cref="Ttl"/> representing the remaining Ttl of the cached item.</returns>
    public Ttl GetTtl(Context context, object? result) => new(_ttl);
}

View on GitHub (pinned to d0e46bdb1e)

Solutions

  1. Pass a non-negative TimeSpan (zero is allowed but useless; use a positive value).
  2. Validate/clamp the configured ttl to TimeSpan.Zero (or a sane minimum) before constructing RelativeTtl.
  3. If the value comes from config, default to a sensible positive ttl when the configured value is invalid.

Example fix

// before
var ttl = configuredEnd - DateTime.UtcNow; // could be negative
new RelativeTtl(ttl);
// after
var ttl = configuredEnd - DateTime.UtcNow;
new RelativeTtl(ttl < TimeSpan.Zero ? TimeSpan.Zero : ttl);
Defensive patterns

Strategy: validation

Validate before calling

if (ttl < TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(ttl), "ttl must be non-negative.");
var strategy = new RelativeTtl(ttl);

Type guard

static bool IsTtlValid(TimeSpan ttl) => ttl >= TimeSpan.Zero;

Prevention

When it happens

Trigger: Constructing new RelativeTtl(negativeTimeSpan), or calling a Cache(...) overload that internally wraps a TimeSpan ttl in a RelativeTtl with a negative value. Subtracting two DateTimes that overflowed, or a misconfigured negative ttl from config, both produce this.

Common situations: TTL read from configuration parsed as negative; a TimeSpan computed by subtraction that went negative; accidentally passing -duration or TimeSpan.FromMilliseconds(-1).

Related errors


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