HangfireIO/Hangfire · error · ArgumentException

The type `{method.DeclaringType}` must be derived from the `

Error message

The type `{method.DeclaringType}` must be derived from the `{type}` type.

What it means

ArgumentException thrown by Job.Validate when the method's DeclaringType is not assignable to the specified job Type. Hangfire allows passing an explicit type (e.g., an interface) with a method declared on a different type, but requires method.DeclaringType.IsAssignableFrom(type) — i.e., the job type must be the same as or derive from/implement the method's declaring type. This catches mismatches where a method and type are unrelated, which would cause invocation-time InvalidCastExceptions or missing-method errors in the performer.

Source

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

        {
            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.");
            }

            var parameters = method.GetParameters();

            if (parameters.Length != argumentCount)
            {
                throw new ArgumentException(
                    "Argument count must be equal to method parameter count.",
                    argumentParameterName);
            }

View on GitHub (pinned to c236dd0f93)

Solutions

  1. Ensure the Type passed to the Job constructor (or TType) is the method's DeclaringType or a type that inherits/implements it.
  2. When using reflection, derive the type from method.DeclaringType rather than hard-coding.
  3. Use the FromExpression overloads which infer the type automatically from the expression.

Example fix

// before — type/method mismatch
var method = typeof(EmailService).GetMethod("Send");
var job = new Job(typeof(ReportService), method, args);

// after — type matches the method's declaring type
var job = new Job(typeof(EmailService), method, args);
// or infer from expression
var job = Job.FromExpression<EmailService>(x => x.Send());
Defensive patterns

Strategy: validation

Validate before calling

if (!method.DeclaringType.GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))
    throw new ArgumentException($"Type {type} does not declare or inherit method {method.Name} (declared on {method.DeclaringType}).");

Type guard

public static bool TypeMatchesMethod(Type type, MethodInfo method)
    => method?.DeclaringType != null && method.DeclaringType.GetTypeInfo().IsAssignableFrom(type?.GetTypeInfo());

Try / catch

try { var job = new Job(type, method, args); }
catch (ArgumentException ex) when (ex.Message.Contains("must be derived from")) { /* align type with method.DeclaringType */ }

Prevention

When it happens

Trigger: Constructing new Job(typeof(Foo), typeof(Bar).GetMethod("Run")) where Bar does not declare or inherit Run; passing a MethodInfo from an unrelated class; enqueuing via the typed overload with a TType that does not declare the method.

Common situations: Copy-paste errors when building Job from reflection; refactoring a method to a different class without updating the type argument; using a MethodInfo from a base class but passing a derived type that does not actually inherit it (e.g., shadowing).

Related errors


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