microsoft/autogen · error · InvalidOperationException
Method {methodInfo.Name} must return a ValueTask or ValueTas
Error message
Method {methodInfo.Name} must return a ValueTask or ValueTask<T> What it means
Thrown by HandlerInvoker when the handler method's return type is neither ValueTask nor ValueTask<T>. The dispatcher type-erases handler results into ValueTask<object?> and requires the ValueTask-based shape; Task-returning or synchronous handlers are rejected at invoker construction time.
Source
Thrown at dotnet/src/Microsoft.AutoGen/Core/HandlerInvoker.cs:65
{
MethodInfo typeEraseAwait = typeof(HandlerInvoker)
.GetMethod(nameof(TypeEraseAwait), BindingFlags.NonPublic | BindingFlags.Static)!
.MakeGenericMethod(methodInfo.ReturnType.GetGenericArguments()[0]);
getResultAsync = async
(object? message, MessageContext messageContext) =>
{
object valueTask = invocation(message, messageContext)!;
object? typelessValueTask = typeEraseAwait.Invoke(null, new object[] { valueTask });
Debug.Assert(typelessValueTask is ValueTask<object?>);
return await (ValueTask<object?>)typelessValueTask;
};
}
else
{
throw new InvalidOperationException($"Method {methodInfo.Name} must return a ValueTask or ValueTask<T>");
}
this.Invocation = getResultAsync;
}
private Func<object?, MessageContext, ValueTask<object?>> Invocation { get; }
public ValueTask<object?> InvokeAsync(object? obj, MessageContext messageContext)
{
return this.Invocation(obj, messageContext);
}
}
View on GitHub (pinned to 027ecf0a37)
Solutions
- Declare handlers as `public ValueTask HandleAsync(T message, MessageContext ctx)` or `ValueTask<TResult>`
- Change Task-returning bodies to `return ValueTask.CompletedTask;` style instead of async Task
- After upgrading the framework, recheck handler signatures against the current IHandle<T> contract
Example fix
// before
public async Task HandleAsync(MyMessage msg, MessageContext ctx) { ... }
// after
public async ValueTask HandleAsync(MyMessage msg, MessageContext ctx) { ... } Defensive patterns
Strategy: validation
Validate before calling
var rt = methodInfo.ReturnType;
if (!typeof(ValueTask).IsAssignableFrom(rt) && !(rt.IsGenericType && rt.GetGenericTypeDefinition() == typeof(ValueTask<>)))
throw new InvalidOperationException($"{methodInfo.Name} must return ValueTask or ValueTask<T>"); Type guard
static bool IsValueTaskHandler(MethodInfo m)
{
var t = m.ReturnType;
return t == typeof(ValueTask) || (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(ValueTask<>));
} Try / catch
try { new HandlerInvoker(method, target); } catch (InvalidOperationException ex) when (ex.Message.Contains("must return a ValueTask")) { throw new InvalidOperationException($"Handler {method.Name} signature invalid; change return type to ValueTask", ex); } Prevention
- Declare handlers as ValueTask/ValueTask<T> from the start
- Re-check handler signatures after framework upgrades
When it happens
Trigger: An IHandle<T>.HandleAsync implementation declared as `public async Task HandleAsync(...)` or `public void HandleAsync(...)` instead of ValueTask/ValueTask<T>; signature drift after upgrading the framework when handlers changed shape.
Common situations: Porting handlers written for a Task-based API; auto-fix or AI tooling rewriting ValueTask to Task; copying sample handlers from an older version.
Related errors
- No handler method found for interface {interface_.FullName}
- Target must be provided for non-static methods
- Could not create chat manager
- Could not create chat manager; make sure that it contains a
- Failed to create instance of {input.FullName}
AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15).
Data as JSON: /api/errors/a3c33e19f45606b8.
Report an issue: GitHub.