{"record":{"id":"ef52ee2662737caa","repo":"App-vNext/Polly","slug":"the-ttl-for-items-to-cache-must-be-greater-than-ze","errorCode":null,"errorMessage":"The ttl for items to cache must be greater than zero.","messagePattern":"The ttl for items to cache must be greater than zero\\.","errorType":"validation","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"src/Polly/Caching/RelativeTtl.cs","lineNumber":19,"sourceCode":"﻿#nullable enable\nnamespace Polly.Caching;\n\n/// <summary>\n/// Defines a ttl strategy which will cache items for the specified time.\n/// </summary>\npublic class RelativeTtl : ITtlStrategy\n{\n    private readonly TimeSpan _ttl;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"RelativeTtl\"/> class.\n    /// </summary>\n    /// <param name=\"ttl\">The timespan for which to consider the cache item valid.</param>\n    public RelativeTtl(TimeSpan ttl)\n    {\n        if (ttl < TimeSpan.Zero)\n        {\n            throw new ArgumentOutOfRangeException(nameof(ttl), \"The ttl for items to cache must be greater than zero.\");\n        }\n\n        _ttl = ttl;\n    }\n\n    /// <summary>\n    /// Gets a TTL for a cacheable item, given the current execution context.\n    /// </summary>\n    /// <param name=\"context\">The execution context.</param>\n    /// <param name=\"result\">The execution result.</param>\n    /// <returns>A <see cref=\"Ttl\"/> representing the remaining Ttl of the cached item.</returns>\n    public Ttl GetTtl(Context context, object? result) => new(_ttl);\n}\n","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/App-vNext/Polly/blob/d0e46bdb1ee11ea50d0e4b6846d2633d6bc09bac/src/Polly/Caching/RelativeTtl.cs#L1-L33","documentation":"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.","triggerScenarios":"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.","commonSituations":"TTL read from configuration parsed as negative; a TimeSpan computed by subtraction that went negative; accidentally passing -duration or TimeSpan.FromMilliseconds(-1).","solutions":["Pass a non-negative TimeSpan (zero is allowed but useless; use a positive value).","Validate/clamp the configured ttl to TimeSpan.Zero (or a sane minimum) before constructing RelativeTtl.","If the value comes from config, default to a sensible positive ttl when the configured value is invalid."],"exampleFix":"// before\nvar ttl = configuredEnd - DateTime.UtcNow; // could be negative\nnew RelativeTtl(ttl);\n// after\nvar ttl = configuredEnd - DateTime.UtcNow;\nnew RelativeTtl(ttl < TimeSpan.Zero ? TimeSpan.Zero : ttl);","handlingStrategy":"validation","validationCode":"if (ttl < TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(ttl), \"ttl must be non-negative.\");\nvar strategy = new RelativeTtl(ttl);","typeGuard":"static bool IsTtlValid(TimeSpan ttl) => ttl >= TimeSpan.Zero;","tryCatchPattern":null,"preventionTips":["Clamp any config-derived ttl to TimeSpan.Zero (or a positive minimum) before constructing RelativeTtl.","When computing ttl as end - now, guard against now being past end.","Validate config ttl in a startup check with a sensible default."],"tags":["polly","caching","legacy-v7","argument-out-of-range","ttl","configuration"],"backgroundTag":null,"analyzedSha":"d0e46bdb1ee11ea50d0e4b6846d2633d6bc09bac","analyzedAt":"2026-08-13T16:36:01.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}