{"record":{"id":"0c36b86d346a7433","repo":"HangfireIO/Hangfire","slug":"expression-body-should-be-of-type-methodcallexpre","errorCode":null,"errorMessage":"Expression body should be of type `MethodCallExpression`","messagePattern":"Expression body should be of type `MethodCallExpression`","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Hangfire.Core/Common/Job.cs","lineNumber":427,"sourceCode":"        /// </remarks>\n        public static Job FromExpression<TType>([NotNull, InstantHandle] Expression<Func<TType, Task>> methodCall)\n        {\n            return FromExpression(methodCall, null);\n        }\n\n        public static Job FromExpression<TType>([NotNull, InstantHandle] Expression<Func<TType, Task>> methodCall, [CanBeNull] string queue)\n        {\n            return FromExpression(methodCall, typeof(TType), queue);\n        }\n\n        private static Job FromExpression([NotNull] LambdaExpression methodCall, [CanBeNull] Type explicitType, [CanBeNull] string queue)\n        {\n            if (methodCall == null) throw new ArgumentNullException(nameof(methodCall));\n\n            var callExpression = methodCall.Body as MethodCallExpression;\n            if (callExpression == null)\n            {\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                }","sourceCodeStart":409,"sourceCodeEnd":445,"githubUrl":"https://github.com/HangfireIO/Hangfire/blob/c236dd0f930f831ec151e436e138ddc429a02a72/src/Hangfire.Core/Common/Job.cs#L409-L445","documentation":"ArgumentException thrown by Job.FromExpression when the supplied lambda's Body is not a MethodCallExpression. Hangfire builds a Job by extracting the target method, type, and arguments from a method-call expression tree; other body types (e.g., a property access MemberExpression, a bare constant, an assignment, or a lambda invoking a delegate) do not represent an invokable method and cannot be serialized. This fires synchronously at enqueue time before any storage interaction.","triggerScenarios":"Passing () => someProperty, () => 42, () => field, or () => func.Invoke() to BackgroundJob.Enqueue/FromExpression; wrapping the method call in an extra lambda; using a ternary or null-coalescing expression as the body; passing an expression that constructs an object rather than calling a method.","commonSituations":"Refactoring a method call into a property accessor or field read; mistakenly enqueuing a delegate invocation; building expressions dynamically with Expression.Lambda where the body is not a MethodCall; copy-paste errors where the lambda body is a value not a call.","solutions":["Ensure the lambda body is a direct method call, e.g. () => service.DoWork(arg).","If targeting an instance method, use the typed overload Enqueue<T>(x => x.DoWork()).","When building expressions dynamically, construct a MethodCallExpression via Expression.Call before wrapping in a lambda."],"exampleFix":"// before — body is not a method call\nBackgroundJob.Enqueue(() => _counter);\nBackgroundJob.Enqueue(() => func.Invoke());\n\n// after\nBackgroundJob.Enqueue(() => service.ReadCounter());\nBackgroundJob.Enqueue<MyService>(x => x.DoWork());","handlingStrategy":"type-guard","validationCode":"if (methodCall.Body is not MethodCallExpression)\n    throw new ArgumentException(\"Lambda body must be a method call, e.g. () => service.Method(args).\", nameof(methodCall));","typeGuard":"public static bool IsMethodCallExpression<T>(Expression<T> expr)\n    => expr?.Body is MethodCallExpression;","tryCatchPattern":"try { var job = Job.FromExpression(() => svc.Work()); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"MethodCallExpression\")) { /* rewrite the lambda to a real method call */ }","preventionTips":["Always write enqueue lambdas as a single method call: () => receiver.Method(args).","Avoid property reads, field reads, delegate invocations, and compound expressions as the lambda body.","Prefer the typed overloads BackgroundJob.Enqueue<T>(x => x.Method()) for clarity."],"tags":["argument","expression-tree","job-definition","client"],"backgroundTag":null,"analyzedSha":"c236dd0f930f831ec151e436e138ddc429a02a72","analyzedAt":"2026-08-13T20:27:11.027Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}