HangfireIO/Hangfire · error · ArgumentNullException

activator

Error message

activator

What it means

Thrown as ArgumentNullException by the obsolete Job.Perform method when the 'activator' JobActivator argument is null. Perform uses the activator to instantiate the target type before invoking the method; a null activator prevents any instance creation, so it is rejected at line 51. This obsolete API mirrors the modern CoreBackgroundJobPerformer pipeline.

Source

Thrown at src/Hangfire.Core/Obsolete/Job.Obsolete.cs:51

            if (arguments == null) throw new ArgumentNullException(nameof(arguments));

            Validate(type, nameof(type), method, nameof(method), arguments.Length, nameof(arguments));

            Type = type;
            Method = method;
            Args = InvocationData.DeserializeArguments(method, arguments);
        }

        /// <exclude />
        [NotNull]
        [Obsolete("Please use `Args` property instead to avoid unnecessary serializations/deserializations. Will be deleted in 2.0.0.")]
        public string[] Arguments => InvocationData.SerializeArguments(Method, Args);

        /// <exclude />
        [Obsolete("This method is deprecated. Please use `CoreBackgroundJobPerformer` or `BackgroundJobPerformer` classes instead. Will be removed in 2.0.0.")]
        public object Perform(JobActivator activator, IJobCancellationToken cancellationToken)
        {
            if (activator == null) throw new ArgumentNullException(nameof(activator));
            if (cancellationToken == null) throw new ArgumentNullException(nameof(cancellationToken));

            object instance = null;

            object result;
            try
            {
                if (!Method.IsStatic)
                {
                    instance = Activate(activator);
                }

                var arguments = GetArguments(cancellationToken);
                result = InvokeMethod(instance, arguments, cancellationToken);
            }
            finally
            {
                Dispose(instance);

View on GitHub (pinned to c236dd0f93)

Solutions

  1. Migrate to CoreBackgroundJobPerformer or BackgroundJobPerformer, which obtain the activator from the configured scope and handle this internally.
  2. If you must use the obsolete Perform, pass a non-null JobActivator instance — e.g. JobActivator.Current or a DI-resolved activator.
  3. Ensure your DI container registers and resolves the JobActivator before performing the job.

Example fix

// before
var result = job.Perform(null, token);

// after
var performer = new CoreBackgroundJobPerformer(JobActivator.Current, ...);
// or, with the obsolete API:
var result = job.Perform(JobActivator.Current, token);
Defensive patterns

Strategy: validation

Validate before calling

var activator = JobActivator.Current;
if (activator == null) throw new InvalidOperationException("No JobActivator configured.");
var result = job.Perform(activator, token);

Try / catch

try { job.Perform(activator, token); }
catch (ArgumentNullException ex) when (ex.ParamName == "activator") { /* configure activator */ }

Prevention

When it happens

Trigger: Calling job.Perform(null, cancellationToken) — i.e. invoking job execution manually without supplying a JobActivator, or passing a field that was never initialized (default JobActivator.Current is a fallback only if you read it; the parameter itself is still null).

Common situations: Custom hosting or test harnesses that call Job.Perform directly without wiring JobActivator.Current or passing an instance; migration from the obsolete Perform API to the performer pipeline where the activator reference was dropped; code that assumes Perform uses a global default and passes null intentionally.

Related errors


AI-assisted analysis of HangfireIO/Hangfire@c236dd0f93 (2026-08-13). Data as JSON: /api/errors/1c80df68112e66c8. Report an issue: GitHub.