microsoft/autogen · error · InvalidOperationException

Target must be provided for non-static methods

Error message

Target must be provided for non-static methods

What it means

Thrown by HandlerInvoker's constructor when a non-static MethodInfo is supplied without a target instance to invoke it on. HandlerInvoker wraps a reflected handler method; instance methods require the agent object as target, static methods can be invoked with null. In framework code the target is always the agent, so this guards custom/misuse construction.

Source

Thrown at dotnet/src/Microsoft.AutoGen/Core/HandlerInvoker.cs:33

        return await vt;
    }

    public HandlerInvoker(MethodInfo methodInfo, object? target = null)
    {
        // TODO: Check that the MethodInfo params check out?

        Func<object?, MessageContext, object?> invocation;
        if (target != null)
        {
            invocation = (object? message, MessageContext messageContext) => methodInfo.Invoke(target, new object?[] { message, messageContext });
        }
        else if (methodInfo.IsStatic)
        {
            invocation = (object? message, MessageContext messageContext) => methodInfo.Invoke(null, new object?[] { message, messageContext });
        }
        else
        {
            throw new InvalidOperationException("Target must be provided for non-static methods");
        }

        Func<object?, MessageContext, ValueTask<object?>> getResultAsync;
        if (methodInfo.ReturnType.IsAssignableFrom(typeof(ValueTask)))
        {
            getResultAsync = async
            (object? message, MessageContext messageContext) =>
            {
                await (ValueTask)invocation(message, messageContext)!;
                return null;
            };
        }
        else if (methodInfo.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>))
        {
            MethodInfo typeEraseAwait = typeof(HandlerInvoker)
                    .GetMethod(nameof(TypeEraseAwait), BindingFlags.NonPublic | BindingFlags.Static)!
                    .MakeGenericMethod(methodInfo.ReturnType.GetGenericArguments()[0]);

View on GitHub (pinned to 027ecf0a37)

Solutions

  1. Pass the owning agent instance as target when the method is an instance method
  2. Keep handler methods static only if you will invoke them without a target
  3. Prefer letting BaseAgent build invokers itself rather than constructing HandlerInvoker manually

Example fix

// before
var invoker = new HandlerInvoker(typeof(MyAgent).GetMethod(nameof(MyAgent.HandleAsync))!, null); // instance method, no target

// after
var invoker = new HandlerInvoker(typeof(MyAgent).GetMethod(nameof(MyAgent.HandleAsync))!, agentInstance);
Defensive patterns

Strategy: validation

Validate before calling

if (!methodInfo.IsStatic && target is null) throw new InvalidOperationException($"Instance method {methodInfo.Name} requires a target");

Try / catch

try { new HandlerInvoker(methodInfo, target); } catch (InvalidOperationException ex) when (ex.Message == "Target must be provided for non-static methods") { throw new InvalidOperationException($"Handler {methodInfo.Name} must be static or given the agent instance", ex); }

Prevention

When it happens

Trigger: Constructing new HandlerInvoker(instanceMethodInfo, target: null) for a method that is not static; passing a MethodInfo obtained from a different (non-static) member while building custom dispatch plumbing.

Common situations: Custom message dispatch layers reusing HandlerInvoker with reflection code that loses the target; refactor changing a handler from static to instance while custom wiring still passes null.

Related errors


AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15). Data as JSON: /api/errors/81536cbd189c5344. Report an issue: GitHub.