{"record":{"id":"a18199a985971710","repo":"App-vNext/Polly","slug":"value-cannot-be-null-a18199","errorCode":null,"errorMessage":"Value cannot be null.","messagePattern":"Value cannot be null\\.","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"src/Polly/Caching/AsyncCacheSyntax.cs","lineNumber":52,"sourceCode":"\n    /// <summary>\n    /// <para>Builds an <see cref=\"AsyncPolicy\"/> that will function like a result cache for delegate executions returning a result.</para>\n    /// <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\"/>.\n    /// 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.\n    /// </para>\n    /// </summary>\n    /// <param name=\"cacheProvider\">The cache provider.</param>\n    /// <param name=\"ttl\">Duration (ttl) for which to cache values.</param>\n    /// <param name=\"cacheKeyStrategy\">The cache key strategy.</param>\n    /// <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>\n    /// <returns>The policy instance.</returns>\n    /// <exception cref=\"ArgumentNullException\">Thrown when <paramref name=\"cacheProvider\"/> is <see langword=\"null\"/>.</exception>\n    /// <exception cref=\"ArgumentNullException\">Thrown when <paramref name=\"cacheKeyStrategy\"/> is <see langword=\"null\"/>.</exception>\n    public static AsyncCachePolicy CacheAsync(IAsyncCacheProvider cacheProvider, TimeSpan ttl, ICacheKeyStrategy cacheKeyStrategy, Action<Context, string, Exception>? onCacheError = null)\n    {\n        if (cacheKeyStrategy is null)\n        {\n            throw new ArgumentNullException(nameof(cacheKeyStrategy));\n        }\n\n        return CacheAsync(cacheProvider, new RelativeTtl(ttl), cacheKeyStrategy.GetCacheKey, onCacheError);\n    }\n\n    /// <summary>\n    /// <para>Builds an <see cref=\"AsyncPolicy\" /> that will function like a result cache for delegate executions returning a result.</para>\n    /// <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\"/>.\n    /// 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.\n    /// </para>\n    /// </summary>\n    /// <param name=\"cacheProvider\">The cache provider.</param>\n    /// <param name=\"ttlStrategy\">A strategy for specifying ttl for values to be cached.</param>\n    /// <param name=\"cacheKeyStrategy\">The cache key strategy.</param>\n    /// <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>\n    /// <returns>The policy instance.</returns>\n    /// <exception cref=\"ArgumentNullException\">Thrown when <paramref name=\"cacheProvider\"/> is <see langword=\"null\"/>.</exception>\n    /// <exception cref=\"ArgumentNullException\">Thrown when <paramref name=\"ttlStrategy\"/> is <see langword=\"null\"/>.</exception>","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/App-vNext/Polly/blob/d0e46bdb1ee11ea50d0e4b6846d2633d6bc09bac/src/Polly/Caching/AsyncCacheSyntax.cs#L34-L70","documentation":"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.","triggerScenarios":"Calling Policy.CacheAsync(cacheProvider, ttl, (ICacheKeyStrategy)null) — passing null as the ICacheKeyStrategy parameter. The guard fires before the RelativeTtl and GetCacheKey wrapping occurs.","commonSituations":"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.","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"],"exampleFix":"// before\nvar policy = Policy.CacheAsync(provider, TimeSpan.FromMinutes(5), (ICacheKeyStrategy)null); // throws\n\n// after\nvar policy = Policy.CacheAsync(provider, TimeSpan.FromMinutes(5), new ContextualTtl());\n// or use the Func overload:\nvar policy = Policy.CacheAsync(provider, TimeSpan.FromMinutes(5), ctx => ctx.OperationKey);","handlingStrategy":"validation","validationCode":"if (cacheKeyStrategy is null)\n{\n    throw new InvalidOperationException(\"Cache key strategy is required.\");\n}\nvar policy = Policy.CacheAsync(provider, ttl, cacheKeyStrategy);","typeGuard":"public static bool IsNonNullStrategy(ICacheKeyStrategy strategy) => strategy is not null;","tryCatchPattern":null,"preventionTips":["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"],"tags":["cache","null-argument","configuration","cache-key-strategy","construction"],"backgroundTag":null,"analyzedSha":"d0e46bdb1ee11ea50d0e4b6846d2633d6bc09bac","analyzedAt":"2026-08-13T16:36:01.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}