{"record":{"id":"e84dd195ed7772cb","repo":"HangfireIO/Hangfire","slug":"global-methods-are-not-supported-use-class-method","errorCode":null,"errorMessage":"Global methods are not supported. Use class methods instead.","messagePattern":"Global methods are not supported\\. Use class methods instead\\.","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"src/Hangfire.Core/Common/Job.cs","lineNumber":487,"sourceCode":"            // ReSharper disable once UnusedParameter.Local\n            [InvokerParameterName] string methodParameterName,\n            // ReSharper disable once UnusedParameter.Local\n            int argumentCount,\n            [InvokerParameterName] string argumentParameterName)\n        {\n            if (!method.IsPublic)\n            {\n                throw new NotSupportedException(\"Only public methods can be invoked in the background. Ensure your method has the `public` access modifier, and you aren't using explicit interface implementation.\");\n            }\n\n            if (method.ContainsGenericParameters)\n            {\n                throw new NotSupportedException(\"Job method can not contain unassigned generic type parameters.\");\n            }\n\n            if (method.DeclaringType == null)\n            {\n                throw new NotSupportedException(\"Global methods are not supported. Use class methods instead.\");\n            }\n\n            if (!method.DeclaringType.GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))\n            {\n                throw new ArgumentException(\n                    $\"The type `{method.DeclaringType}` must be derived from the `{type}` type.\",\n                    typeParameterName);\n            }\n\n            if (method.ReturnType == typeof(void) &&\n                AsyncStateMachineAttributeCache.GetOrAdd(method, static m => m.GetCustomAttribute<AsyncStateMachineAttribute>()) != null)\n            {\n                throw new NotSupportedException(\"Async void methods are not supported. Use async Task instead.\");\n            }\n\n            var parameters = method.GetParameters();\n\n            if (parameters.Length != argumentCount)","sourceCodeStart":469,"sourceCodeEnd":505,"githubUrl":"https://github.com/HangfireIO/Hangfire/blob/c236dd0f930f831ec151e436e138ddc429a02a72/src/Hangfire.Core/Common/Job.cs#L469-L505","documentation":"NotSupportedException thrown by Job.Validate when method.DeclaringType is null, which occurs for top-level (global) functions in some languages or for dynamically emitted methods that have no declaring type. Hangfire requires job methods to belong to a type so it can serialize the type name and locate it by reflection when performing the job elsewhere. Methods without a declaring type cannot be located reliably across process boundaries.","triggerScenarios":"Enqueuing a local function (C#) whose DeclaringType may be a compiler-generated type (rarely null but can be exotic); F# module-level functions; dynamically generated methods via DynamicMethod or Reflection.Emit with no declaring type; some interop scenarios.","commonSituations":"Using F# top-level functions as job methods; enqueuing a DynamicMethod; reflection-based construction where MethodInfo comes from an unsupported source; edge cases with compiler-generated closure classes.","solutions":["Move the job method into a static or instance class so it has a concrete DeclaringType.","For F#, place functions in a type (a member) rather than at module level.","Avoid enqueuing DynamicMethod or Reflection.Emit methods — define a real method on a real type."],"exampleFix":"// before — F# module-level function / global-style\nlet doWork () = ... // module function, may have no usable declaring type\nBackgroundJob.Enqueue(() -> doWork())\n\n// after — wrap in a type\ntype Worker() =\n    member _.DoWork() = ...\nBackgroundJob.Enqueue<Worker>(fun x -> x.DoWork())","handlingStrategy":"validation","validationCode":"if (method.DeclaringType == null)\n    throw new NotSupportedException(\"Job method has no declaring type; move it into a class.\");","typeGuard":"public static bool HasDeclaringType(MethodInfo m) => m?.DeclaringType != null;","tryCatchPattern":null,"preventionTips":["Define job methods on static or instance classes, never at module/function top level.","For F#, place job functions inside a type member.","Never enqueue DynamicMethod or Reflection.Emit-generated methods."],"tags":["not-supported","job-definition","reflection","declaring-type"],"backgroundTag":null,"analyzedSha":"c236dd0f930f831ec151e436e138ddc429a02a72","analyzedAt":"2026-08-13T20:27:11.027Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}