dotnet/aspnetcore · error · ArgumentOutOfRangeException
The absolute expiration value must be in the future.
Error message
The absolute expiration value must be in the future.
What it means
Thrown by RedisCache.GetAbsoluteExpiration (line 600) during a Set/SetAsync operation when DistributedCacheEntryOptions.AbsoluteExpiration is set but its value is less than or equal to creationTime (DateTimeOffset.UtcNow). An absolute expiration at or before the current time means the item is immediately expired and is rejected. The exception type is ArgumentOutOfRangeException.
Source
Thrown at src/Caching/StackExchangeRedis/src/RedisCache.cs:600
options.SlidingExpiration.Value.TotalSeconds);
}
else if (absoluteExpiration.HasValue)
{
return (long)(absoluteExpiration.Value - creationTime).TotalSeconds;
}
else if (options.SlidingExpiration.HasValue)
{
return (long)options.SlidingExpiration.Value.TotalSeconds;
}
return null;
}
private static DateTimeOffset? GetAbsoluteExpiration(DateTimeOffset creationTime, DistributedCacheEntryOptions options)
{
if (options.AbsoluteExpiration.HasValue && options.AbsoluteExpiration <= creationTime)
{
#pragma warning disable CA2208 // Instantiate argument exceptions correctly
throw new ArgumentOutOfRangeException(
nameof(DistributedCacheEntryOptions.AbsoluteExpiration),
options.AbsoluteExpiration.Value,
"The absolute expiration value must be in the future.");
#pragma warning restore CA2208 // Instantiate argument exceptions correctly
}
if (options.AbsoluteExpirationRelativeToNow.HasValue)
{
return creationTime + options.AbsoluteExpirationRelativeToNow;
}
return options.AbsoluteExpiration;
}
/// <inheritdoc />
public void Dispose()
{
if (_disposed)View on GitHub (pinned to 294cab2f9b)
Solutions
- Use AbsoluteExpirationRelativeToNow instead of a fixed AbsoluteExpiration to avoid clock/timezone issues: options.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1).
- If using AbsoluteExpiration, ensure it is a future UTC DateTimeOffset and add a small buffer for clock skew.
- Add a pre-check: if (options.AbsoluteExpiration <= DateTimeOffset.UtcNow) recompute or skip caching.
Example fix
// before — fixed absolute time that may be in the past by the time Set runs
var opts = new DistributedCacheEntryOptions
{
AbsoluteExpiration = somePreviouslyComputedDateTimeOffset
};
await cache.SetStringAsync("key", value, opts);
// after — relative duration, immune to past-time errors
var opts = new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30)
};
await cache.SetStringAsync("key", value, opts); Defensive patterns
Strategy: validation
Validate before calling
// Guard before calling Set
if (options.AbsoluteExpiration.HasValue && options.AbsoluteExpiration.Value <= DateTimeOffset.UtcNow)
{
throw new ArgumentOutOfRangeException(nameof(options.AbsoluteExpiration),
"AbsoluteExpiration must be in the future.");
} Type guard
static bool IsValidAbsoluteExpiration(DistributedCacheEntryOptions opts)
=> !opts.AbsoluteExpiration.HasValue || opts.AbsoluteExpiration.Value > DateTimeOffset.UtcNow; Try / catch
try
{
await cache.SetAsync(key, value, options);
}
catch (ArgumentOutOfRangeException ex) when (ex.Message.Contains("absolute expiration"))
{
options.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1);
await cache.SetAsync(key, value, options);
} Prevention
- Prefer AbsoluteExpirationRelativeToNow to sidestep clock-skew and timezone issues.
- Add a pre-check ensuring AbsoluteExpiration is strictly in the future before caching.
When it happens
Trigger: RedisCache.SetImpl or SetImplAsync calls GetAbsoluteExpiration (line 595) with options.AbsoluteExpiration <= DateTimeOffset.UtcNow. This applies to the AbsoluteExpiration property (a fixed DateTimeOffset), not AbsoluteExpirationRelativeToNow.
Common situations: Clock skew between the client computing the expiration and the Redis cache host; passing a previously-computed DateTimeOffset that has since passed; incorrect UTC conversion from a local time; deserializing a cached options object whose AbsoluteExpiration is now in the past.
Related errors
- The absolute expiration value must be in the future.
- Either absolute or sliding expiration needs to be provided.
- ExpiredItemsDeletionInterval cannot be less than the minimum
- The sliding expiration value must be positive.
- Circuit options have already been configured.
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/f8a6168dc8ccd9dd.
Report an issue: GitHub.