{"record":{"id":"fd280ad5e4935784","repo":"App-vNext/Polly","slug":"value-cannot-be-null-parameter-oncacheput","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'onCachePut')","messagePattern":"Value cannot be null\\. \\(Parameter 'onCachePut'\\)","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"src/Polly/Caching/AsyncCacheTResultSyntax.cs","lineNumber":1006,"sourceCode":"\n        if (cacheKeyStrategy == null)\n        {\n            throw new ArgumentNullException(nameof(cacheKeyStrategy));\n        }\n\n        if (onCacheGet == null)\n        {\n            throw new ArgumentNullException(nameof(onCacheGet));\n        }\n\n        if (onCacheMiss == null)\n        {\n            throw new ArgumentNullException(nameof(onCacheMiss));\n        }\n\n        if (onCachePut == null)\n        {\n            throw new ArgumentNullException(nameof(onCachePut));\n        }\n\n        return new AsyncCachePolicy<TResult>(cacheProvider, ttlStrategy, cacheKeyStrategy, onCacheGet, onCacheMiss, onCachePut, onCacheGetError, onCachePutError);\n    }\n\n    private static void EmptyCallback(Context context, string key)\n    {\n        // No-op\n    }\n}\n","sourceCodeStart":988,"sourceCodeEnd":1017,"githubUrl":"https://github.com/App-vNext/Polly/blob/d0e46bdb1ee11ea50d0e4b6846d2633d6bc09bac/src/Polly/Caching/AsyncCacheTResultSyntax.cs#L988-L1017","documentation":"Thrown by the terminal CacheAsync<TResult>(...) overload when onCachePut is null. The put callback is the last mandatory lifecycle hook in this overload; a null would NPE when storing a fresh value, so construction is rejected. All preceding guards run first.","triggerScenarios":"Calling the full overload with null for the onCachePut Action<Context,string>.","commonSituations":"Believing the callback is optional; refactor dropped the assignment; passing null placeholders from a builder that did not wire all callbacks.","solutions":["Provide a non-null Action<Context,string> for onCachePut (a no-op is fine).","Switch to a simpler overload that defaults to EmptyCallback when you do not need put notifications.","Null-check at the call site."],"exampleFix":"// before\nvar policy = Policy.CacheAsync<string>(provider, ttlStrategy, keyFunc, onGet, onMiss, null, null, null);\n// after\nAction<Context, string> noop = (_, _) => { };\nvar policy = Policy.CacheAsync<string>(provider, ttlStrategy, keyFunc, onGet, onMiss, noop, null, null);","handlingStrategy":"validation","validationCode":"Action<Context, string> onPut = onCachePut ?? ((_, _) => { });\nvar policy = Policy.CacheAsync<TResult>(provider, ttlStrategy, keyFunc, onGet, onMiss, onPut, null, null);","typeGuard":"static bool HasCallback(Action<Context, string>? a) => a is not null;","tryCatchPattern":"try { var p = Policy.CacheAsync<R>(provider, ttl, keyFunc, onGet, onMiss, onPut, null, null); }\ncatch (ArgumentNullException ex) when (ex.ParamName == \"onCachePut\") { /* supply a no-op callback */ }","preventionTips":["Coalesce the put callback to a no-op.","Prefer simpler overloads that default callbacks.","Enable nullable reference types."],"tags":["caching","argumentnullexception","null-argument","polly-v7","cache-callback"],"backgroundTag":null,"analyzedSha":"d0e46bdb1ee11ea50d0e4b6846d2633d6bc09bac","analyzedAt":"2026-08-13T16:36:01.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}