App-vNext/Polly · error · ArgumentNullException
Value cannot be null. (Parameter 'cacheKeyStrategy')
Error message
Value cannot be null. (Parameter 'cacheKeyStrategy')
What it means
Thrown at policy-construction time by the legacy Polly v7 CachePolicy factory Policy.Cache(ISyncCacheProvider, TimeSpan, ICacheKeyStrategy, ...). The overload that takes a custom ICacheKeyStrategy requires it to be non-null because the policy derives every cache key from cacheKeyStrategy.GetCacheKey. Polly fails fast with ArgumentNullException rather than throwing a NullReferenceException later when a delegate executes.
Source
Thrown at src/Polly/Caching/CacheSyntax.cs:56
/// If the <paramref name="cacheProvider "/> provides a value from cache, 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 CachePolicy Cache(
ISyncCacheProvider cacheProvider,
TimeSpan ttl,
ICacheKeyStrategy cacheKeyStrategy,
Action<Context, string, Exception>? onCacheError = null)
{
if (cacheKeyStrategy is null)
{
throw new ArgumentNullException(nameof(cacheKeyStrategy));
}
return Cache(cacheProvider, new RelativeTtl(ttl), cacheKeyStrategy.GetCacheKey, onCacheError);
}
/// <summary>
/// <para>Builds a <see cref="Policy"/> 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 from cache, 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
- Pass a non-null ICacheKeyStrategy instance to the overload.
- If you want default key derivation from Context.OperationKey, use the simpler overload Policy.Cache(cacheProvider, ttl) which supplies DefaultCacheKeyStrategy.Instance for you.
- Fix the DI registration / factory so the strategy is never null before the call.
Example fix
// before Policy.Cache(provider, ttl, (ICacheKeyStrategy)null); // after Policy.Cache(provider, ttl); // uses DefaultCacheKeyStrategy (Context.OperationKey)
Defensive patterns
Strategy: validation
Validate before calling
if (cacheKeyStrategy is null) throw new InvalidOperationException("cacheKeyStrategy must be configured before building the cache policy.");
var policy = Policy.Cache(cacheProvider, ttl, cacheKeyStrategy); Type guard
static bool IsKeyStrategyValid(Polly.Caching.ICacheKeyStrategy? s) => s is not null;
Prevention
- Prefer the simpler Policy.Cache(provider, ttl) overload unless you need a custom key strategy.
- Resolve the ICacheKeyStrategy from DI at composition time so a missing registration fails loudly during startup.
- Use a unit test that builds the policy with realistic arguments to catch null wiring.
When it happens
Trigger: Calling Policy.Cache(cacheProvider, ttl, (ICacheKeyStrategy)null) on the overload whose third parameter is ICacheKeyStrategy. A null reference (uninitialized field, a DI-resolved service that came back null, or a conditional factory that returned null) reaches that argument.
Common situations: DI container failed to register or inject the ICacheKeyStrategy; a custom key-strategy property is declared but never assigned; an overload-resolution mistake where you meant to pass a Func<Context,string> but the compiler bound to the ICacheKeyStrategy overload and you passed null.
Related errors
- Value cannot be null. (Parameter 'cacheProvider')
- Value cannot be null. (Parameter 'ttlStrategy')
- Value cannot be null. (Parameter 'onCacheGet')
- Value cannot be null. (Parameter 'onCacheMiss')
- Value cannot be null. (Parameter 'onCachePut')
AI-assisted analysis of App-vNext/Polly@d0e46bdb1e (2026-08-13).
Data as JSON: /api/errors/8e9b64c9e4dfac71.
Report an issue: GitHub.