{"record":{"id":"bbf8252329e1d94f","repo":"HangfireIO/Hangfire","slug":"action-bbf825","errorCode":null,"errorMessage":"action","messagePattern":"action","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"src/Hangfire.Core/Profiling/SlowLogProfiler.cs","lineNumber":45,"sourceCode":"        private readonly ILog _logger;\n\n        public SlowLogProfiler(ILog logger)\n            : this(logger, DefaultThreshold)\n        {\n        }\n\n        public SlowLogProfiler(ILog logger, TimeSpan threshold)\n        {\n            _threshold = threshold;\n            _logger = logger;\n        }\n\n        public TResult InvokeMeasured<TInstance, TResult>(\n            TInstance instance,\n            Func<TInstance, TResult> action,\n            Func<TInstance, string> messageFunc = null)\n        {\n            if (action == null) throw new ArgumentNullException(nameof(action));\n\n            var startedAt = Environment.TickCount;\n\n            // TODO: Change implementation to thread-based, once it is possible to query custom services everywhere\n            using (new Timer(LogWarningMessage, null, _threshold, _threshold))\n            {\n                return action(instance);\n            }\n\n            void LogWarningMessage(object state)\n            {\n                var elapsedSec = unchecked(Environment.TickCount - startedAt) / 1_000;\n\n                var type = instance?.ToString() ?? typeof(TInstance).ToString();\n                var message = messageFunc?.Invoke(instance) ?? \"(null)\";\n\n                _logger.Warn($\"Slow log: {type} is still performing \\\"{message}\\\" after {elapsedSec} sec\");\n            }","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/HangfireIO/Hangfire/blob/c236dd0f930f831ec151e436e138ddc429a02a72/src/Hangfire.Core/Profiling/SlowLogProfiler.cs#L27-L63","documentation":"Thrown by SlowLogProfiler.InvokeMeasured when the action delegate (the work to measure) is null. SlowLogProfiler measures execution time and emits a slow-log warning when a threshold is exceeded. Passing a null action is a programming contract violation — there is nothing to measure and invoke.","triggerScenarios":"Calling slowLogProfiler.InvokeMeasured(instance, null) where the Func<TInstance, TResult> action argument is null. Occurs when a caller builds the action lazily and a factory returns null, or when a code path passes an unresolved delegate.","commonSituations":"Custom Hangfire extensions that wrap operations with the profiler but conditionally pass null when no operation is needed. Refactoring that drops the delegate assignment. DI or factory method returning null for the action.","solutions":["Pass a non-null Func<TInstance, TResult> delegate to InvokeMeasured.","Guard the caller: if the action is null, skip the profiled call entirely instead of forwarding null.","Verify the factory/expression producing the action returns a real delegate."],"exampleFix":"// before\nprofiler.InvokeMeasured(instance, action: nullFunc);\n\n// after\nFunc<MyType, MyResult> action = inst => DoWork(inst);\nprofiler.InvokeMeasured(instance, action);","handlingStrategy":"validation","validationCode":"Func<TInstance, TResult> action = BuildAction();\nif (action == null) throw new InvalidOperationException(\"No action to measure.\");\nprofiler.InvokeMeasured(instance, action);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never pass a delegate that a factory may return null for — check before invoking.","Build actions with a lambda or method group that is guaranteed non-null.","If an operation is optional, skip the profiled call instead of forwarding null."],"tags":["profiling","argument-null","internal"],"backgroundTag":null,"analyzedSha":"c236dd0f930f831ec151e436e138ddc429a02a72","analyzedAt":"2026-08-13T20:27:11.027Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}