{"record":{"id":"6527f1a09509e4c5","repo":"HangfireIO/Hangfire","slug":"only-public-methods-can-be-invoked-in-the-backgrou","errorCode":null,"errorMessage":"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.","messagePattern":"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\\.","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"src/Hangfire.Core/Common/Job.cs","lineNumber":477,"sourceCode":"                type,\n                method,\n                GetExpressionValues(callExpression.Arguments),\n                queue);\n        }\n\n        private static void Validate(\n            Type type, \n            [InvokerParameterName] string typeParameterName,\n            MethodInfo method, \n            // 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            }","sourceCodeStart":459,"sourceCodeEnd":495,"githubUrl":"https://github.com/HangfireIO/Hangfire/blob/c236dd0f930f831ec151e436e138ddc429a02a72/src/Hangfire.Core/Common/Job.cs#L459-L495","documentation":"NotSupportedException thrown by Job.Validate when the target method is not public. Hangfire invokes job methods by reflection in a separate (possibly different) process, so non-public methods (private, protected, internal) and explicit interface implementations are rejected at job-definition time because they cannot be reliably invoked across process boundaries and serialized metadata. The error message explicitly calls out explicit interface implementation as a common culprit (the generated method is private).","triggerScenarios":"Enqueuing () => obj.PrivateMethod(); a method marked internal, protected, or private; a method that is an explicit interface implementation (void IFoo.Bar()) whose backing method is private; a method on an internal type.","commonSituations":"Refactoring a public method to private; using explicit interface implementation and enqueuing the concrete type; enqueuing a method defined on an internal class; F# or VB code where default accessibility differs from C#.","solutions":["Change the method's access modifier to public.","If the method is an explicit interface implementation, enqueue against the interface using BackgroundJob.Enqueue<IFoo>(x => x.Bar()).","Move the job method to a public service class if the current type cannot be made public."],"exampleFix":"// before — private / explicit interface impl\npublic class Worker {\n    void IJob.Run() { ... }      // explicit impl → private backing method\n    private void DoRun() { ... }\n}\nBackgroundJob.Enqueue<Worker>(x => ((IJob)x).Run());\n\n// after — public method, or enqueue against the interface\npublic class Worker : IJob {\n    public void Run() { ... }    // public\n}\nBackgroundJob.Enqueue<IJob>(x => x.Run());","handlingStrategy":"validation","validationCode":"if (!method.IsPublic)\n    throw new NotSupportedException($\"Method {method.Name} must be public to be used as a job method.\");\n// or check at design time: ensure the job method has the 'public' modifier.","typeGuard":"public static bool IsPublicJobMethod(MethodInfo m) => m != null && m.IsPublic;","tryCatchPattern":"try { BackgroundJob.Enqueue<T>(x => x.Work()); }\ncatch (NotSupportedException ex) when (ex.Message.Contains(\"public methods\")) { /* make the method public or enqueue the interface */ }","preventionTips":["Keep job methods public.","For explicit interface implementations, enqueue against the interface type: Enqueue<IFoo>(x => x.Bar()).","Add a unit test that reflects over job methods and asserts IsPublic to catch regressions."],"tags":["not-supported","job-definition","reflection","access-modifier"],"backgroundTag":null,"analyzedSha":"c236dd0f930f831ec151e436e138ddc429a02a72","analyzedAt":"2026-08-13T20:27:11.027Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}