{"record":{"id":"f8a6168dc8ccd9dd","repo":"dotnet/aspnetcore","slug":"the-absolute-expiration-value-must-be-in-the-futur-f8a616","errorCode":null,"errorMessage":"The absolute expiration value must be in the future.","messagePattern":"The absolute expiration value must be in the future\\.","errorType":"exception","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"src/Caching/StackExchangeRedis/src/RedisCache.cs","lineNumber":600,"sourceCode":"                options.SlidingExpiration.Value.TotalSeconds);\n        }\n        else if (absoluteExpiration.HasValue)\n        {\n            return (long)(absoluteExpiration.Value - creationTime).TotalSeconds;\n        }\n        else if (options.SlidingExpiration.HasValue)\n        {\n            return (long)options.SlidingExpiration.Value.TotalSeconds;\n        }\n        return null;\n    }\n\n    private static DateTimeOffset? GetAbsoluteExpiration(DateTimeOffset creationTime, DistributedCacheEntryOptions options)\n    {\n        if (options.AbsoluteExpiration.HasValue && options.AbsoluteExpiration <= creationTime)\n        {\n#pragma warning disable CA2208 // Instantiate argument exceptions correctly\n            throw new ArgumentOutOfRangeException(\n                nameof(DistributedCacheEntryOptions.AbsoluteExpiration),\n                options.AbsoluteExpiration.Value,\n                \"The absolute expiration value must be in the future.\");\n#pragma warning restore CA2208 // Instantiate argument exceptions correctly\n        }\n\n        if (options.AbsoluteExpirationRelativeToNow.HasValue)\n        {\n            return creationTime + options.AbsoluteExpirationRelativeToNow;\n        }\n\n        return options.AbsoluteExpiration;\n    }\n\n    /// <inheritdoc />\n    public void Dispose()\n    {\n        if (_disposed)","sourceCodeStart":582,"sourceCodeEnd":618,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/Caching/StackExchangeRedis/src/RedisCache.cs#L582-L618","documentation":"Thrown by the Redis distributed cache's GetAbsoluteExpiration when AbsoluteExpiration is set and is <= the entry creation time. Unlike the SQL Server variant (228) this throws ArgumentOutOfRangeException. It prevents storing an entry that is already expired at insert.","triggerScenarios":"Calling SetAsync with options.AbsoluteExpiration <= creationTime (the moment the cache started building the entry). This happens when the absolute time is in the past or exactly equal to now.","commonSituations":"Capturing 'now' early and passing a derived absolute time after a delay; clock skew between client and Redis host; timezone mishandling converting to UTC; reusing a cached DateTimeOffset from an earlier request.","solutions":["Use AbsoluteExpirationRelativeToNow (TimeSpan) instead of an absolute DateTimeOffset to sidestep clock/timezone issues.","If you must use AbsoluteExpiration, compute it at the SetAsync call site and ensure it is strictly greater than DateTimeOffset.UtcNow.","Synchronize clocks across servers (NTP) to eliminate skew."],"exampleFix":"// before: absolute time captured early\nvar abs = DateTimeOffset.UtcNow.AddSeconds(1); // could be <= now by the time Set runs\nawait cache.SetStringAsync(key, value, new DistributedCacheEntryOptions { AbsoluteExpiration = abs });\n\n// after: relative offset\nawait cache.SetStringAsync(key, value, new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5) });","handlingStrategy":"validation","validationCode":"if (options.AbsoluteExpiration.HasValue && options.AbsoluteExpiration.Value <= DateTimeOffset.UtcNow) { throw new ArgumentOutOfRangeException(nameof(options.AbsoluteExpiration)); }","typeGuard":"static bool AbsoluteExpirationIsValid(DateTimeOffset? abs) => !abs.HasValue || abs.Value > DateTimeOffset.UtcNow;","tryCatchPattern":null,"preventionTips":["Prefer AbsoluteExpirationRelativeToNow for Redis cache entries.","Recompute absolute times at the call site; never reuse stale timestamps.","Use NTP to keep clocks aligned across cache clients and hosts."],"tags":["caching","redis","aspnetcore","distributed-cache","configuration"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}