I'm getting 'The 'Job' field has a null or empty value' even though I'm sending an ID

Hi guys!

I’m working with recurring jobs and everything was working well until I started to receive the following message,

’The ‘Job’ field has a null or empty value’

The code below is the code that I’m using to “RecurringJob”

RecurringJob.AddOrUpdate(operation.RecurrentJobId, () => ExecuteReaction(Reaction.Oid), cronExpression); 

As you can see, “operation.RecurrentJobId” is a string that I’m assigning for the job Id, however, the process continues, but in the “Application_Error” in global.asax I’m getting the error mentioned before.

Any ideas?

Can you tell me what storage are you using for your jobs? And what version of Hangfire.Core do you have?

We are using Hangfire.Core 1.7.19 and we are using SQL Server Storage.

Can you run the following query to your SQL Server to understand what’s happened with your recurring job? Please note the XXXYYYZZZ value should be substituted with the value behind operation.RecurrentJobId.

SELECT *
  FROM [HangFire].[Hash]
  WHERE [Key] = N'recurring-job:XXXYYYZZZ'
Key Field Value ExpireAt
recurring-job:305a2364-a87b-4aa1-b8d3-1350b57ad77f CreatedAt 1623157844953 NULL
recurring-job:305a2364-a87b-4aa1-b8d3-1350b57ad77f Cron */10 * * * * * NULL
recurring-job:305a2364-a87b-4aa1-b8d3-1350b57ad77f Job {XXXX.Connect.Api.Controllers.ReactionsController, XXXX.Connect.Api,m:ExecuteReaction,p:[System.Guid, mscorlib],a:[\2ca8d4f8-1775-4934-b72a-2981b2bbc32b]} NULL
recurring-job:305a2364-a87b-4aa1-b8d3-1350b57ad77f NextExecution 1623157850000 NULL
recurring-job:305a2364-a87b-4aa1-b8d3-1350b57ad77f Queue default NULL
recurring-job:305a2364-a87b-4aa1-b8d3-1350b57ad77f TimeZoneId UTC NULL
recurring-job:305a2364-a87b-4aa1-b8d3-1350b57ad77f V 2 NULL

Hm, really strange. This exception appears only when Job key isn’t present or when it’s empty (please see the link below). But from the query results above I see it’s present and non-empty. Is it possible that the recurring-job:305a2364-a87b-4aa1-b8d3-1350b57ad77f – Job row was changed manually by some people and that Job value was changed by something like Job (trailing space added) or so? In this case it’s easy to miss the extra space characters when looking at query results.

Hangfire/RecurringJobEntity.cs at master · HangfireIO/Hangfire (github.com)

Try to delete the recurring job, re-create it and let me know once the problem persists.

The issue happens every time that a new recurring job is enqueued. As I wrote here, the process continues, but the exception is thrown after the recurring job is created. In addition, the job isn’t modified manually so I’m pretty sure that that is not the reason for the issue. Last week I saw the code that you just sent, but I couldn’t find something that helped me.

Is there any consistent workflow that leads to this exception? I’ve tried to re-create all the entries in the database and run the AddOrUpdate method, but unfortunately everything was fine. I think that’s a corner case and need to make it reproducible.

First of all, I want to thank you for your help and your time.

The first step that we do is creating a background job as in the following code is shown.

 JobId = BackgroundJob.Enqueue(() => ExecuteReaction(Reaction.Oid));

As you can see, the job is immediate. When the ExecuteReaction method is thrown, we have some business logic, and after that, we create the recurring job with the code that I showed you in the first post. When the recurring job is enqueued, is through an API call where we have all hangfire code.

I’ve had this issue when passing a struct without a public constructor as argument (Reaction.Oid in this case). (Edit; A deserialization issue to be precise)

Ah, recurring jobs (RecurringJob.AddOrUpdate method) and regular jobs (BackgroundJob.* methods) are different entities, use different data structures and can’t be mixed together. But I still don’t understand why the original exception was thrown.

I’ve tried to implement the following struct…

public struct Reaction
{
    private Reaction(string oid)
    {
        Oid = oid;
    }

    public string Oid { get; }

    public static Reaction Create(string oid) => new Reaction(oid);
}

…and create the following recurring job, and everything works fine.

var reaction = Reaction.Create("Hello, world!");
RecurringJob.AddOrUpdate("seconds", () => Console.WriteLine(reaction.Oid), "*/15 * * * * *");