App-vNext/Polly · error · ArgumentNullException
Value cannot be null. (Parameter 'wrappedCacheProvider')
Error message
Value cannot be null. (Parameter 'wrappedCacheProvider')
What it means
Thrown by the AsyncSerializingCacheProvider<TSerialized> constructor (the non-generic-object variant used to cache any object type) when wrappedCacheProvider is null. This provider decorates an inner cache with serialization; without an inner cache there is nothing to serialize into, so construction is rejected inline via the ?? throw expression.
Source
Thrown at src/Polly/Caching/AsyncSerializingCacheProvider.cs:22
/// <summary>
/// Defines an <see cref="IAsyncCacheProvider"/> which serializes objects of any type in and out of an underlying cache which caches as type <typeparamref name="TSerialized"/>. For use with asynchronous <see cref="CachePolicy" />.
/// </summary>
/// <typeparam name="TSerialized">The type of serialized objects to be placed in the cache.</typeparam>
public class AsyncSerializingCacheProvider<TSerialized> : IAsyncCacheProvider
{
private readonly IAsyncCacheProvider<TSerialized> _wrappedCacheProvider;
private readonly ICacheItemSerializer<object, TSerialized> _serializer;
/// <summary>
/// Initializes a new instance of the <see cref="AsyncSerializingCacheProvider{TSerialized}"/> class.
/// </summary>
/// <param name="wrappedCacheProvider">The wrapped cache provider.</param>
/// <param name="serializer">The serializer.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="wrappedCacheProvider"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="serializer"/> is <see langword="null"/>.</exception>
public AsyncSerializingCacheProvider(IAsyncCacheProvider<TSerialized> wrappedCacheProvider, ICacheItemSerializer<object, TSerialized> serializer)
{
_wrappedCacheProvider = wrappedCacheProvider ?? throw new ArgumentNullException(nameof(wrappedCacheProvider));
_serializer = serializer ?? throw new ArgumentNullException(nameof(serializer));
}
/// <summary>
/// Gets a value from the cache asynchronously.
/// </summary>
/// <param name="key">The cache key.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="continueOnCapturedContext">Whether async calls should continue on a captured synchronization context.</param>
/// <returns>
/// A <see cref="Task{TResult}" /> promising as Result a tuple whose first element is a value indicating whether
/// the key was found in the cache, and whose second element is the value from the cache (null if not found).
/// </returns>
public async Task<(bool, object?)> TryGetAsync(string key, CancellationToken cancellationToken, bool continueOnCapturedContext)
{
(bool cacheHit, TSerialized? objectToDeserialize) = await _wrappedCacheProvider.TryGetAsync(key, cancellationToken, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext);
return (cacheHit, cacheHit ? _serializer.Deserialize(objectToDeserialize) : null);
}View on GitHub (pinned to d0e46bdb1e)
Solutions
- Pass a non-null IAsyncCacheProvider<TSerialized> as the wrapped provider.
- Verify the inner provider resolved from DI before constructing the serializer wrapper.
- Null-check at the call site to surface which registration is missing.
Example fix
// before var cp = new AsyncSerializingCacheProvider<byte[]>(null, serializer); // after var inner = new RedisCacheProvider<byte[]>(connection); var cp = new AsyncSerializingCacheProvider<byte[]>(inner, serializer);
Defensive patterns
Strategy: validation
Validate before calling
ArgumentNullException.ThrowIfNull(wrappedCacheProvider); var cp = new AsyncSerializingCacheProvider<TSerialized>(wrappedCacheProvider, serializer);
Type guard
static bool HasInner<T>(IAsyncCacheProvider<T>? p) => p is not null;
Try / catch
try { var cp = new AsyncSerializingCacheProvider<byte[]>(inner, serializer); }
catch (ArgumentNullException ex) when (ex.ParamName == "wrappedCacheProvider") { /* construct inner provider or fail */ } Prevention
- Construct the inner provider at the composition root and null-check it.
- Register the inner IAsyncCacheProvider<TSerialized> in DI and assert resolution.
- Avoid connection-dependent factories that return null on failure.
When it happens
Trigger: Calling new AsyncSerializingCacheProvider<Byte[]>(null, serializer) or passing a wrapped provider field that resolved to null from DI.
Common situations: The inner cache provider (e.g. a Redis-backed IAsyncCacheProvider<byte[]>) was never registered; a factory returned null when its connection failed; tests forgot to construct the inner provider.
Related errors
- Value cannot be null. (Parameter 'ttlStrategy')
- Value cannot be null. (Parameter 'onCacheGet')
- Value cannot be null. (Parameter 'onCacheMiss')
- Value cannot be null. (Parameter 'onCachePut')
- Value cannot be null. (Parameter 'action')
AI-assisted analysis of App-vNext/Polly@d0e46bdb1e (2026-08-13).
Data as JSON: /api/errors/f135fa8dd048ecaa.
Report an issue: GitHub.