HangfireIO/Hangfire · error · NotSupportedException

Only public methods can be invoked in the background. Ensure

Error message

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.

What it means

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).

Source

Thrown at src/Hangfire.Core/Common/Job.cs:477

                type,
                method,
                GetExpressionValues(callExpression.Arguments),
                queue);
        }

        private static void Validate(
            Type type, 
            [InvokerParameterName] string typeParameterName,
            MethodInfo method, 
            // ReSharper disable once UnusedParameter.Local
            [InvokerParameterName] string methodParameterName,
            // ReSharper disable once UnusedParameter.Local
            int argumentCount,
            [InvokerParameterName] string argumentParameterName)
        {
            if (!method.IsPublic)
            {
                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.");
            }

            if (method.ContainsGenericParameters)
            {
                throw new NotSupportedException("Job method can not contain unassigned generic type parameters.");
            }

            if (method.DeclaringType == null)
            {
                throw new NotSupportedException("Global methods are not supported. Use class methods instead.");
            }

            if (!method.DeclaringType.GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))
            {
                throw new ArgumentException(
                    $"The type `{method.DeclaringType}` must be derived from the `{type}` type.",
                    typeParameterName);
            }

View on GitHub (pinned to c236dd0f93)

Solutions

  1. Change the method's access modifier to public.
  2. If the method is an explicit interface implementation, enqueue against the interface using BackgroundJob.Enqueue<IFoo>(x => x.Bar()).
  3. Move the job method to a public service class if the current type cannot be made public.

Example fix

// before — private / explicit interface impl
public class Worker {
    void IJob.Run() { ... }      // explicit impl → private backing method
    private void DoRun() { ... }
}
BackgroundJob.Enqueue<Worker>(x => ((IJob)x).Run());

// after — public method, or enqueue against the interface
public class Worker : IJob {
    public void Run() { ... }    // public
}
BackgroundJob.Enqueue<IJob>(x => x.Run());
Defensive patterns

Strategy: validation

Validate before calling

if (!method.IsPublic)
    throw new NotSupportedException($"Method {method.Name} must be public to be used as a job method.");
// or check at design time: ensure the job method has the 'public' modifier.

Type guard

public static bool IsPublicJobMethod(MethodInfo m) => m != null && m.IsPublic;

Try / catch

try { BackgroundJob.Enqueue<T>(x => x.Work()); }
catch (NotSupportedException ex) when (ex.Message.Contains("public methods")) { /* make the method public or enqueue the interface */ }

Prevention

When it happens

Trigger: 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.

Common situations: 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#.

Related errors


AI-assisted analysis of HangfireIO/Hangfire@c236dd0f93 (2026-08-13). Data as JSON: /api/errors/6527f1a09509e4c5. Report an issue: GitHub.