App-vNext/Polly · error · ArgumentNullException
Value cannot be null.
Error message
Value cannot be null.
What it means
Thrown as ArgumentNullException(nameof(cacheKeyStrategy)) from the CacheAsync overload at AsyncCacheSyntax.cs:52 that accepts an ICacheKeyStrategy. This overload wraps the strategy's GetCacheKey method into a Func<Context, string> and delegates to another overload. The guard at line 50–53 fires before the delegation, ensuring the key strategy is present.
Source
Thrown at src/Polly/Caching/AsyncCacheSyntax.cs:52
/// <summary>
/// <para>Builds an <see cref="AsyncPolicy"/> that will function like a result cache for delegate executions returning a result.</para>
/// <para>Before executing a delegate returning a result, checks whether the <paramref name="cacheProvider"/> holds a value for the cache key determined by applying the <paramref name="cacheKeyStrategy"/> to the execution <see cref="Context"/>.
/// If the <paramref name="cacheProvider"/> provides a value, returns that value and does not execute the governed delegate. If the <paramref name="cacheProvider"/> does not provide a value, executes the governed delegate, stores the value with the <paramref name="cacheProvider"/>, then returns the value.
/// </para>
/// </summary>
/// <param name="cacheProvider">The cache provider.</param>
/// <param name="ttl">Duration (ttl) for which to cache values.</param>
/// <param name="cacheKeyStrategy">The cache key strategy.</param>
/// <param name="onCacheError">Delegate to call if an exception is thrown when attempting to get a value from or put a value into the cache, passing the execution context, the cache key, and the exception.</param>
/// <returns>The policy instance.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="cacheProvider"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="cacheKeyStrategy"/> is <see langword="null"/>.</exception>
public static AsyncCachePolicy CacheAsync(IAsyncCacheProvider cacheProvider, TimeSpan ttl, ICacheKeyStrategy cacheKeyStrategy, Action<Context, string, Exception>? onCacheError = null)
{
if (cacheKeyStrategy is null)
{
throw new ArgumentNullException(nameof(cacheKeyStrategy));
}
return CacheAsync(cacheProvider, new RelativeTtl(ttl), cacheKeyStrategy.GetCacheKey, onCacheError);
}
/// <summary>
/// <para>Builds an <see cref="AsyncPolicy" /> that will function like a result cache for delegate executions returning a result.</para>
/// <para>Before executing a delegate returning a result, checks whether the <paramref name="cacheProvider" /> holds a value for the cache key determined by applying the <paramref name="cacheKeyStrategy"/> to the execution <see cref="Context"/>.
/// If the <paramref name="cacheProvider" /> provides a value, returns that value and does not execute the governed delegate. If the <paramref name="cacheProvider" /> does not provide a value, executes the governed delegate, stores the value with the <paramref name="cacheProvider" />, then returns the value.
/// </para>
/// </summary>
/// <param name="cacheProvider">The cache provider.</param>
/// <param name="ttlStrategy">A strategy for specifying ttl for values to be cached.</param>
/// <param name="cacheKeyStrategy">The cache key strategy.</param>
/// <param name="onCacheError">Delegate to call if an exception is thrown when attempting to get a value from or put a value into the cache, passing the execution context, the cache key, and the exception.</param>
/// <returns>The policy instance.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="cacheProvider"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="ttlStrategy"/> is <see langword="null"/>.</exception>View on GitHub (pinned to d0e46bdb1e)
Solutions
- Provide a non-null ICacheKeyStrategy implementation, e.g. a DefaultCacheKeyStrategy subclass
- Use the Func<Context, string> overload if a full ICacheKeyStrategy class is unnecessary
- Ensure DI registration for the strategy resolves to a non-null instance
Example fix
// before var policy = Policy.CacheAsync(provider, TimeSpan.FromMinutes(5), (ICacheKeyStrategy)null); // throws // after var policy = Policy.CacheAsync(provider, TimeSpan.FromMinutes(5), new ContextualTtl()); // or use the Func overload: var policy = Policy.CacheAsync(provider, TimeSpan.FromMinutes(5), ctx => ctx.OperationKey);
Defensive patterns
Strategy: validation
Validate before calling
if (cacheKeyStrategy is null)
{
throw new InvalidOperationException("Cache key strategy is required.");
}
var policy = Policy.CacheAsync(provider, ttl, cacheKeyStrategy); Type guard
public static bool IsNonNullStrategy(ICacheKeyStrategy strategy) => strategy is not null;
Prevention
- Provide a concrete ICacheKeyStrategy or use the Func<Context, string> overload
- Register ICacheKeyStrategy in DI and use GetRequiredService
- Prefer the Func overload (ctx => ctx.OperationKey) for simple key derivation
When it happens
Trigger: Calling Policy.CacheAsync(cacheProvider, ttl, (ICacheKeyStrategy)null) — passing null as the ICacheKeyStrategy parameter. The guard fires before the RelativeTtl and GetCacheKey wrapping occurs.
Common situations: Calling the overload that takes ICacheKeyStrategy without providing a strategy (use the overload with Func<Context,string> instead). DI container returning null for the strategy registration. Migrating between cache key strategy types and forgetting to pass the new instance.
Related errors
- Value cannot be null.
- Value cannot be null.
- Value must be greater than zero.
- Value must be greater than or equal to zero.
- Value must be greater than zero.
AI-assisted analysis of App-vNext/Polly@d0e46bdb1e (2026-08-13).
Data as JSON: /api/errors/a18199a985971710.
Report an issue: GitHub.