microsoft/autogen · error · InvalidOperationException
Control message is missing a destination. Message: '{control
Error message
Control message is missing a destination. Message: '{controlMsg}' What it means
InvalidOperationException thrown in GrpcGateway.DispatchControlMessageAsync when a ControlMessage has an empty or null Destination. Control messages are forwarded verbatim to a destination worker over its response stream; with no destination the gateway has no way to route the write, so it refuses the message.
Source
Thrown at dotnet/src/Microsoft.AutoGen/RuntimeGateway.Grpc/Services/Grpc/GrpcGateway.cs:546
/// <summary>
/// Writes a response to a worker connection.
/// </summary>
/// <param name="connection">The worker connection.</param>
/// <param name="cloudEvent">The cloud event.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
private async Task WriteResponseAsync(GrpcWorkerConnection<Message> connection, CloudEvent cloudEvent, CancellationToken cancellationToken = default)
{
await connection.ResponseStream.WriteAsync(new Message { CloudEvent = cloudEvent }, cancellationToken).ConfigureAwait(false);
}
private async ValueTask DispatchControlMessageAsync<TMessage>(GrpcWorkerConnection<TMessage> connection, ControlMessage controlMsg, CancellationToken cancellationToken)
where TMessage : class
{
if (string.IsNullOrEmpty(controlMsg.Destination))
{
throw new InvalidOperationException($"Control message is missing a destination. Message: '{controlMsg}'");
}
// Ensure the control message is of the correct type
if (controlMsg is TMessage typedResponseMessage)
{
// Send the response back to the client
await connection.ResponseStream.WriteAsync(typedResponseMessage, cancellationToken).ConfigureAwait(false);
}
else
{
throw new InvalidOperationException($"Cannot convert control message to type {typeof(TMessage).Name}");
}
}
}
View on GitHub (pinned to 027ecf0a37)
Solutions
- Always populate ControlMessage.Destination with the target worker/agent identity before dispatch.
- If the message is meant for the originating worker, set Destination to that worker's client id before sending.
- Add a unit test over your control-message builders asserting Destination is non-empty.
Example fix
// before
var msg = new ControlMessage { Command = "reload" };
// after
var msg = new ControlMessage { Destination = clientId, Command = "reload" }; Defensive patterns
Strategy: validation
Validate before calling
if (string.IsNullOrEmpty(controlMsg?.Destination))
{
throw new ArgumentException($"ControlMessage requires a Destination: {controlMsg}");
} Type guard
static bool IsRoutable(ControlMessage msg) => !string.IsNullOrEmpty(msg?.Destination);
Try / catch
try { await DispatchControlMessageAsync(connection, controlMsg, ct); }
catch (InvalidOperationException ex) when (ex.Message.Contains("missing a destination"))
{
_logger.LogError("Discarding control message without destination: {@Msg}", controlMsg);
} Prevention
- Always set Destination when constructing control messages; treat it as required.
- Add a builder/factory for control messages that refuses to emit without a destination.
- Unit test all control-message constructors for non-empty Destination.
When it happens
Trigger: A worker or gateway component emitting a ControlMessage without setting Destination (for example a keep-alive or ack built by hand); string.Empty slipping through a serializer default; control-plane code paths that broadcast rather than target a single worker.
Common situations: Custom control-protocol extensions that added new message kinds but forgot the destination field; proto3 field-presence pitfalls where an unset string serializes as "" and passes IsNullOrEmpty checks only on the gateway side; version mismatch between gateway and worker control-message schemas.
Related errors
- Request message is missing a target. Message: '{request}'.
- Cannot convert control message to type {typeof(TMessage).Nam
- All agents must have a name.
- All agents must have a unique name.
- All agents in the workflow must be in the group chat.
AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15).
Data as JSON: /api/errors/8e7c379dd9b11bd0.
Report an issue: GitHub.