{"record":{"id":"ca5009f379015dbc","repo":"HangfireIO/Hangfire","slug":"expression-object-should-be-not-null","errorCode":null,"errorMessage":"Expression object should be not null.","messagePattern":"Expression object should be not null\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Hangfire.Core/Common/Job.cs","lineNumber":444,"sourceCode":"            {\n                throw new ArgumentException(\"Expression body should be of type `MethodCallExpression`\", nameof(methodCall));\n            }\n\n            var type = explicitType ?? callExpression.Method.DeclaringType;\n            var method = callExpression.Method;\n\n            if (explicitType == null && callExpression.Object != null)\n            {\n                // Creating a job that is based on a scope variable. We should infer its\n                // type and method based on its value, and not from the expression tree.\n\n                // TODO: BREAKING: Consider removing this special case entirely.\n                // People consider that the whole object is serialized, this is not true.\n\n                var objectValue = GetExpressionValue(callExpression.Object);\n                if (objectValue == null)\n                {\n                    throw new InvalidOperationException(\"Expression object should be not null.\");\n                }\n\n                // TODO: BREAKING: Consider using `callExpression.Object.Type` expression instead.\n                type = objectValue.GetType();\n\n                // If an expression tree is based on interface, we should use its own\n                // MethodInfo instance, based on the same method name and parameter types.\n                method = type.GetNonOpenMatchingMethod(\n                    callExpression.Method.Name,\n                    callExpression.Method.GetParameters().Select(static x => x.ParameterType).ToArray());\n            }\n\n            return new Job(\n                // ReSharper disable once AssignNullToNotNullAttribute\n                type,\n                method,\n                GetExpressionValues(callExpression.Arguments),\n                queue);","sourceCodeStart":426,"sourceCodeEnd":462,"githubUrl":"https://github.com/HangfireIO/Hangfire/blob/c236dd0f930f831ec151e436e138ddc429a02a72/src/Hangfire.Core/Common/Job.cs#L426-L462","documentation":"InvalidOperationException thrown by Job.FromExpression when the expression's instance object (callExpression.Object) evaluates to null at job-creation time. When you enqueue an instance method via a closure (e.g., () => myService.DoWork()), Hangfire evaluates the captured object to infer its concrete runtime type — the object is used only for type discovery, not serialized. A null instance means the target's type cannot be determined, so Hangfire refuses to build the job. Note this only applies when no explicit TType is provided (the typed overloads FromExpression<T> bypass this path).","triggerScenarios":"Enqueuing () => instance.Method() where instance is null at enqueue time; passing a service resolved from DI that returned null; a field/property that was not initialized before the enqueue call.","commonSituations":"Constructor-injected service that is null due to missing DI registration; enqueuing from a static context where the instance field is not yet set; Lazy<T> whose Value was never accessed; null returned from a factory method used inline in the lambda.","solutions":["Use the typed overload BackgroundJob.Enqueue<TService>(x => x.DoWork()) so Hangfire uses typeof(TService) and does not evaluate the instance.","Ensure the captured instance is non-null before enqueueing — validate DI registrations and initialization order.","For interface-based services, register the concrete type in DI and use the typed overload to avoid runtime evaluation entirely."],"exampleFix":"// before — instance may be null\nvar service = ResolveService(); // could be null\nBackgroundJob.Enqueue(() => service.DoWork());\n\n// after — typed overload, no instance evaluation\nBackgroundJob.Enqueue<IMyService>(x => x.DoWork());","handlingStrategy":"type-guard","validationCode":"// Prefer typed overloads that avoid instance evaluation:\n// BackgroundJob.Enqueue<TService>(x => x.Work())\n// If using an instance closure, ensure the instance is non-null:\nif (instance == null) throw new InvalidOperationException(\"Job target instance is null; register it in DI or use the typed overload.\");","typeGuard":"public static bool IsInstanceResolvable(Expression<Action> expr)\n    => expr.Body is MethodCallExpression mc && (mc.Object == null || GetExpressionValueSafe(mc.Object) != null);","tryCatchPattern":"try { BackgroundJob.Enqueue(() => instance.Work()); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"Expression object should be not null\")) { /* switch to Enqueue<T> or fix DI */ }","preventionTips":["Use the typed overload BackgroundJob.Enqueue<T>(x => x.Work()) so Hangfire uses typeof(T) and skips instance evaluation.","Validate DI registrations for job services before the first enqueue.","Avoid enqueuing against fields/properties that may be lazily initialized."],"tags":["null-reference","expression-tree","job-definition","di"],"backgroundTag":null,"analyzedSha":"c236dd0f930f831ec151e436e138ddc429a02a72","analyzedAt":"2026-08-13T20:27:11.027Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}