HangfireIO/Hangfire · error · NotSupportedException

Job method can not contain unassigned generic type parameter

Error message

Job method can not contain unassigned generic type parameters.

What it means

NotSupportedException thrown by Job.Validate when method.ContainsGenericParameters is true — i.e., the method has open (unassigned) generic type parameters. Because jobs are serialized and invoked in a possibly different process by name and serialized arguments, the runtime cannot reconstruct a closed generic method from an unassigned type parameter. The check fires when a generic method is enqueued without the type arguments being inferable/assigned at definition time.

Source

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

        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);
            }

            if (method.ReturnType == typeof(void) &&
                AsyncStateMachineAttributeCache.GetOrAdd(method, static m => m.GetCustomAttribute<AsyncStateMachineAttribute>()) != null)
            {
                throw new NotSupportedException("Async void methods are not supported. Use async Task instead.");

View on GitHub (pinned to c236dd0f93)

Solutions

  1. Make the method non-generic by fixing the argument type, or close the generic at call site: BackgroundJob.Enqueue(() => service.GenericMethod<int>(42)).
  2. If using a MethodInfo directly, call method.MakeGenericMethod(typeof(int)) to produce a closed method before constructing the Job.
  3. Wrap the generic method in a non-generic public method that internally calls the generic one.

Example fix

// before — open generic parameter
public class Worker {
    public void Run<T>(T arg) { ... }
}
BackgroundJob.Enqueue(() => worker.Run(someValue)); // T unbound at def site

// after — concrete method or closed generic
public class Worker {
    public void RunInt(int arg) { ... }
}
BackgroundJob.Enqueue<Worker>(x => x.RunInt(42));
Defensive patterns

Strategy: validation

Validate before calling

if (method.ContainsGenericParameters)
    throw new NotSupportedException("Job method has open generic parameters; close them before creating the job.");
var closed = method.IsGenericMethodDefinition ? method.MakeGenericMethod(typeof(int)) : method;

Type guard

public static bool IsClosedGenericMethod(MethodInfo m)
    => m != null && !m.ContainsGenericParameters;

Try / catch

try { BackgroundJob.Enqueue(() => svc.Run<T>(arg)); }
catch (NotSupportedException ex) when (ex.Message.Contains("generic type parameters")) { /* close the generic or wrap in a non-generic method */ }

Prevention

When it happens

Trigger: Enqueuing () => service.GenericMethod<T>() where T is not bound; a method declared as void Run<T>(T arg) enqueued without a concrete T; reflection-supplied MethodInfo that still has ContainsGenericParameters == true.

Common situations: Building a generic job method and forgetting to close it; enqueuing via a MethodInfo obtained from reflection on an open generic method definition; dynamic dispatch scenarios where the type argument is not pinned.

Related errors


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