microsoft/autogen · error · InvalidOperationException

Unexpected message '{message}'.

Error message

Unexpected message '{message}'.

What it means

Thrown in OnMessageAsync when the Message oneof case is none of Request, Response, or CloudEvent — most commonly MessageOneofCase.None (an unset message) or a case added in a newer protocol version. The runtime treats any unrecognized shape as a protocol violation.

Source

Thrown at dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentRuntime.cs:487

    public async ValueTask OnMessageAsync(Message message, CancellationToken cancellation = default)
    {
        switch (message.MessageCase)
        {
            case Message.MessageOneofCase.Request:
                var request = message.Request ?? throw new InvalidOperationException("Request is null.");
                await HandleRequest(request);
                break;
            case Message.MessageOneofCase.Response:
                var response = message.Response ?? throw new InvalidOperationException("Response is null.");
                await HandleResponse(response);
                break;
            case Message.MessageOneofCase.CloudEvent:
                var cloudEvent = message.CloudEvent ?? throw new InvalidOperationException("CloudEvent is null.");
                await HandlePublish(cloudEvent);
                break;
            default:
                throw new InvalidOperationException($"Unexpected message '{message}'.");
        }
    }
}

View on GitHub (pinned to 027ecf0a37)

Solutions

  1. Ensure every Message sent has exactly one of Request, Response, or CloudEvent set
  2. Align client SDK and runtime versions so both sides understand the same oneof cases
  3. Add a guard before dispatch: skip/log messages with MessageCase == MessageOneofCase.None

Example fix

// before
await router.SendAsync(new Message()); // empty -> throws

// after
if (msg.MessageCase == Message.MessageOneofCase.None) { /* skip */ }
else { await runtime.OnMessageAsync(msg); }
Defensive patterns

Strategy: validation

Validate before calling

if (msg.MessageCase is not (Message.MessageOneofCase.Request or Message.MessageOneofCase.Response or Message.MessageOneofCase.CloudEvent))
{
    _logger.LogWarning("Dropping unsupported message case {Case}", msg.MessageCase);
    return;
}

Type guard

static bool IsSupported(Message m) => m.MessageCase is Message.MessageOneofCase.Request or Message.MessageOneofCase.Response or Message.MessageOneofCase.CloudEvent;

Try / catch

try { await runtime.OnMessageAsync(msg); } catch (InvalidOperationException ex) when (ex.Message.Contains("Unexpected message")) { _logger.LogWarning(ex, "Unsupported message case"); }

Prevention

When it happens

Trigger: Sending new Message() with no oneof field set; sending a message whose oneof case exists only in a newer proto (e.g. a new message kind) to an older runtime; deserialization errors that leave the oneof unset.

Common situations: Version skew between client SDK and runtime (new message kinds not understood by the old side); accidental dispatch of empty messages; fire-and-forget code paths that construct Message without payload.

Related errors


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