HangfireIO/Hangfire · error · InvalidOperationException

The 'Job' field has a null or empty value

Error message

The 'Job' field has a null or empty value

What it means

Thrown by TriggerRecurringJob when the RecurringJobEntity.Job payload is null, meaning the recurring job entry in storage has no serialized job definition. Hangfire cannot create a background job without a target method, so triggering is impossible. This usually means the storage entry is incomplete or corrupt.

Source

Thrown at src/Hangfire.Core/RecurringJobExtensions.cs:112

        }

        public static BackgroundJob TriggerRecurringJob(
            [NotNull] this IBackgroundJobFactory factory,
            [NotNull] JobStorage storage,
            [NotNull] IStorageConnection connection,
            [NotNull] IProfiler profiler,
            [NotNull] RecurringJobEntity recurringJob,
            DateTime now)
        {
            if (factory == null) throw new ArgumentNullException(nameof(factory));
            if (storage == null) throw new ArgumentNullException(nameof(storage));
            if (connection == null) throw new ArgumentNullException(nameof(connection));
            if (profiler == null) throw new ArgumentNullException(nameof(profiler));
            if (recurringJob == null) throw new ArgumentNullException(nameof(recurringJob));

            if (recurringJob.Job == null)
            {
                throw new InvalidOperationException("The 'Job' field has a null or empty value");
            }

            var job = InvocationData.DeserializePayload(recurringJob.Job).DeserializeJob();

            var context = new CreateContext(storage, connection, job, null, null, profiler, null);
            context.Parameters["RecurringJobId"] = recurringJob.RecurringJobId;
            context.Parameters["Time"] = JobHelper.ToTimestamp(now);

            var backgroundJob = factory.Create(context);

            recurringJob.LastExecution = now;
            recurringJob.LastJobId = backgroundJob?.Id;

            return backgroundJob;
        }

        public static void EnqueueBackgroundJob(
            [NotNull] this IStateMachine stateMachine,

View on GitHub (pinned to c236dd0f93)

Solutions

  1. Recreate the recurring job with RecurringJob.AddOrUpdate to restore the serialized Job payload.
  2. Remove the orphaned entry from the 'recurring-jobs' set if it is no longer needed (RecurringJob.RemoveIfExists).
  3. If using a custom storage, verify that AddOrUpdate persists the Job field atomically alongside the set membership.

Example fix

// before — triggering a corrupt entry
RecurringJob.Trigger("broken-job"); // throws

// after — recreate then trigger
RecurringJob.AddOrUpdate("broken-job", () => Work(), Cron.Daily());
RecurringJob.Trigger("broken-job");
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate the recurring job has a Job payload before triggering
var job = connection.GetRecurringJobs().FirstOrDefault(j => j.Id == id);
if (job?.Job == null) { /* recreate or skip */ }

Try / catch

try { RecurringJob.Trigger(id); }
catch (InvalidOperationException ex) when (ex.Message.Contains("'Job' field"))
{
    RecurringJob.AddOrUpdate(id, () => Work(), cron);
}

Prevention

When it happens

Trigger: Calling RecurringJob.Trigger(id) or the scheduler processing a recurring job whose 'Job' hash field is missing or empty. Also reachable through IBackgroundJobFactory.TriggerRecurringJob directly.

Common situations: A recurring job was partially written to storage (interrupted write, custom storage bug). Manual deletion of the Job field. A migration or storage switch that dropped the payload. Triggering a job that was never fully created via AddOrUpdate.

Related errors


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