{"record":{"id":"cfde29e26773ee59","repo":"HangfireIO/Hangfire","slug":"callback","errorCode":null,"errorMessage":"callback","messagePattern":"callback","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"src/Hangfire.Core/Processing/BackgroundExecution.cs","lineNumber":73,"sourceCode":"            _options = options ?? throw new ArgumentNullException(nameof(options));\n\n            _logger = LogProvider.GetLogger(GetType());\n            _createdAt = Stopwatch.StartNew();\n\n            _stopToken = stopToken;\n\n            _stopRegistration = _stopToken.Register(SetStoppedAt);\n\n#if !NETSTANDARD1_3\n            AppDomainUnloadMonitor.EnsureInitialized();\n#endif\n        }\n\n        public bool StopRequested => _disposed || _stopToken.IsCancellationRequested;\n\n        public void Run(Action<Guid, object> callback, object state)\n        {\n            if (callback == null) throw new ArgumentNullException(nameof(callback));\n\n            var executionId = Guid.NewGuid();\n\n            // ExecutionId is a custom correlation id for logging purposes. We can use Thread's\n            // ManagedThreadId property here, but it's better to have a single implementation between\n            // sync and async dispatchers - async one can execute related tasks on different threads,\n            // so ManagedThreadId doesn't work there.\n            //using (LogProvider.OpenMappedContext(\"ExecutionId\", executionId.ToString()))\n            {\n#if !NETSTANDARD1_3\n                try\n#endif\n                {\n                    HandleStarted(executionId, out var nextDelay);\n\n                    // There should be no operations between the `while` and `try` blocks to\n                    // avoid unintended stopping due to ThreadAbortException between the loop\n                    // iterations. Even loop condition is placed into the `try` block.","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/HangfireIO/Hangfire/blob/c236dd0f930f831ec151e436e138ddc429a02a72/src/Hangfire.Core/Processing/BackgroundExecution.cs#L55-L91","documentation":"Thrown by BackgroundExecution.Run (internal) when the synchronous callback Action<Guid, object> is null. Run invokes callback(executionId, state) inside the retry loop, so a null delegate would throw NRE mid-loop.","triggerScenarios":"Calling backgroundExecution.Run(null, state). The execution is driven by a dispatcher that passes its _action; if that action delegate was null the error surfaces here.","commonSituations":"A dispatcher constructed with a null action whose check was bypassed; a test harness calling Run directly with a null lambda; a refactor that left the callback argument empty.","solutions":["Pass a non-null Action<Guid, object> callback to Run.","Ensure the dispatcher's action delegate is validated at construction (BackgroundDispatcher already checks action for null).","In tests, supply even a no-op callback `(_, __) => { }`."],"exampleFix":"// before\nexecution.Run(null, state);\n\n// after\nexecution.Run((id, s) => DoWork(id, s), state);","handlingStrategy":"validation","validationCode":"if (callback == null) throw new ArgumentNullException(nameof(callback));\nexecution.Run(callback, state);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate the callback at the dispatcher that supplies it (already done in BackgroundDispatcher).","In tests, pass a no-op `(_, __) => { }` rather than null.","Never construct a dispatcher with a null action."],"tags":["hangfire","null-argument","argument-validation","background-processing"],"backgroundTag":null,"analyzedSha":"c236dd0f930f831ec151e436e138ddc429a02a72","analyzedAt":"2026-08-13T20:27:11.027Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}