{"record":{"id":"2479f585bb7967b3","repo":"HangfireIO/Hangfire","slug":"statemachine","errorCode":null,"errorMessage":"stateMachine","messagePattern":"stateMachine","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"src/Hangfire.Core/Client/CoreBackgroundJobFactory.cs","lineNumber":38,"sourceCode":"using System.Threading;\nusing Hangfire.Annotations;\nusing Hangfire.Common;\nusing Hangfire.Logging;\nusing Hangfire.States;\nusing Hangfire.Storage;\n\nnamespace Hangfire.Client\n{\n    internal sealed class CoreBackgroundJobFactory : IBackgroundJobFactory\n    {\n        private readonly ILog _logger = LogProvider.GetLogger(typeof(CoreBackgroundJobFactory));\n        private readonly object _syncRoot = new object();\n        private int _retryAttempts;\n        private Func<int, TimeSpan> _retryDelayFunc;\n\n        public CoreBackgroundJobFactory([NotNull] IStateMachine stateMachine)\n        {\n            StateMachine = stateMachine ?? throw new ArgumentNullException(nameof(stateMachine));\n            RetryAttempts = 0;\n            RetryDelayFunc = GetRetryDelay;\n        }\n\n        public IStateMachine StateMachine { get; }\n\n        public int RetryAttempts\n        {\n            get { lock (_syncRoot) { return _retryAttempts; } }\n            set { lock (_syncRoot) { _retryAttempts = value; } }\n        }\n\n        public Func<int, TimeSpan> RetryDelayFunc\n        {\n            get { lock (_syncRoot) { return _retryDelayFunc; } }\n            set { lock (_syncRoot) { _retryDelayFunc = value; } }\n        }\n","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/HangfireIO/Hangfire/blob/c236dd0f930f831ec151e436e138ddc429a02a72/src/Hangfire.Core/Client/CoreBackgroundJobFactory.cs#L20-L56","documentation":"Thrown by the CoreBackgroundJobFactory constructor when stateMachine is null. CoreBackgroundJobFactory is the inner factory that actually persists a job and applies its initial state via IStateMachine.ApplyState. The state machine is required to transition a newly created job into its EnqueuedState/ScheduledState etc. Because CoreBackgroundJobFactory is internal and normally constructed by BackgroundJobFactory (which wires a StateMachine(filterProvider)), a null here indicates a broken custom factory or reflection-based instantiation.","triggerScenarios":"Reflectively instantiating CoreBackgroundJobFactory with a null IStateMachine; a custom IBackgroundJobFactory that internally builds CoreBackgroundJobFactory incorrectly; DI containers that fail to resolve IStateMachine.","commonSituations":"Custom factory wrappers that bypass the BackgroundJobFactory constructor; test harnesses that new-up CoreBackgroundJobFactory without a StateMachine; advanced scenarios replacing the state-machine pipeline.","solutions":["Use BackgroundJobFactory (the public decorator) which constructs CoreBackgroundJobFactory with a properly wired StateMachine(filterProvider).","When constructing manually, pass a valid IStateMachine such as new StateMachine(JobFilterProviders.Providers).","Register IStateMachine in your DI container if resolving CoreBackgroundJobFactory directly."],"exampleFix":"// before\nvar factory = new CoreBackgroundJobFactory(null);\n\n// after\nvar stateMachine = new StateMachine(JobFilterProviders.Providers);\nvar factory = new CoreBackgroundJobFactory(stateMachine);","handlingStrategy":"validation","validationCode":"var stateMachine = providedStateMachine ?? new StateMachine(JobFilterProviders.Providers);\nvar factory = new CoreBackgroundJobFactory(stateMachine);","typeGuard":"public static bool IsValidStateMachine(IStateMachine sm)\n    => sm != null;","tryCatchPattern":null,"preventionTips":["Use the public BackgroundJobFactory decorator which wires the StateMachine automatically.","Register IStateMachine in DI if constructing CoreBackgroundJobFactory directly.","Avoid instantiating internal CoreBackgroundJobFactory via reflection."],"tags":["argument-null","job-factory","state-machine"],"backgroundTag":null,"analyzedSha":"c236dd0f930f831ec151e436e138ddc429a02a72","analyzedAt":"2026-08-13T20:27:11.027Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}