HangfireIO/Hangfire · error · InvalidOperationException

Unsupported filter instance

Error message

Unsupported filter instance

What it means

JobFilterCollection.ValidateFilterInstance (JobFilterCollection.cs:143) guards Add/AddRange calls: only objects implementing at least one Hangfire filter interface (IClientFilter, IServerFilter, IClientExceptionFilter, IServerExceptionFilter, IApplyStateFilter, IElectStateFilter) are accepted. Anything else is rejected because the filter pipeline cannot invoke lifecycle hooks on an incompatible object.

Source

Thrown at src/Hangfire.Core/Common/JobFilterCollection.cs:143

        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        // ReSharper disable once UnusedParameter.Local
        private static void ValidateFilterInstance(object instance)
        {
            if (instance != null &&
                !(instance is IClientFilter 
                || instance is IServerFilter 
                || instance is IClientExceptionFilter 
                || instance is IServerExceptionFilter
                || instance is IApplyStateFilter
                || instance is IElectStateFilter))
            {
                throw new InvalidOperationException("Unsupported filter instance");
            }
        }
    }
}

View on GitHub (pinned to c236dd0f93)

Solutions

  1. Make the class implement the appropriate Hangfire filter interface (IServerFilter for server-side OnPerforming/OnPerformed, IClientFilter for client-side, etc.).
  2. Verify the type implements one of: IClientFilter, IServerFilter, IClientExceptionFilter, IServerExceptionFilter, IApplyStateFilter, IElectStateFilter.
  3. If it is a third-party type, wrap it in an adapter class that implements the correct interface.

Example fix

// before
public class RequestLogger { public void Log() { ... } }
GlobalJobFilters.Filters.Add(new RequestLogger());

// after
public class RequestLogger : IServerFilter
{
    public void OnPerforming(PerformingContext ctx) { /* log */ }
    public void OnPerformed(PerformedContext ctx) { }
}
GlobalJobFilters.Filters.Add(new RequestLogger());
Defensive patterns

Strategy: type-guard

Validate before calling

static bool IsHangfireFilter(object instance) =>
    instance is IClientFilter ||
    instance is IServerFilter ||
    instance is IClientExceptionFilter ||
    instance is IServerExceptionFilter ||
    instance is IApplyStateFilter ||
    instance is IElectStateFilter;

if (!IsHangfireFilter(myInstance))
    throw new InvalidOperationException($"{myInstance.GetType()} is not a Hangfire filter.");
GlobalJobFilters.Filters.Add(myInstance);

Type guard

static bool IsHangfireFilter(object instance) =>
    instance is IClientFilter ||
    instance is IServerFilter ||
    instance is IClientExceptionFilter ||
    instance is IServerExceptionFilter ||
    instance is IApplyStateFilter ||
    instance is IElectStateFilter;

Prevention

When it happens

Trigger: Calling GlobalJobFilters.Filters.Add(someObject) or jobFilterCollection.Add(instance) where instance does not implement any of the six recognized filter interfaces.

Common situations: Registering a plain class, a logging middleware, or a third-party attribute that is not a Hangfire filter; accidentally adding a service instance meant for DI; adding an MVC/ASP.NET filter attribute instead of a Hangfire one.

Related errors


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