microsoft/autogen · error · InvalidOperationException

Message must have a receiver to be sent.

Error message

Message must have a receiver to be sent.

What it means

InProcessRuntime.SendMessageServicer is the callback invoked for point-to-point message deliveries. Before dispatching, it requires the MessageEnvelope to carry a Receiver (an AgentId); a delivery without one is a programming error because there is no agent to hand the message to. The guard throws InvalidOperationException as soon as the servicer runs, i.e. when the queued delivery is processed, not when it is enqueued.

Source

Thrown at dotnet/src/Microsoft.AutoGen/Core/InProcessRuntime.cs:106

    public ValueTask PublishMessageAsync(object message, TopicId topic, AgentId? sender = null, string? messageId = null, CancellationToken cancellation = default)
    {
        return this.ExecuteTracedAsync(() =>
        {
            MessageDelivery delivery = new MessageEnvelope(message, messageId, cancellation)
                                        .WithSender(sender)
                                        .ForPublish(topic, this.PublishMessageServicer);

            this.messageDeliveryQueue.Enqueue(delivery);

            return delivery.FutureNoResult;
        });
    }

    private async ValueTask<object?> SendMessageServicer(MessageEnvelope envelope, CancellationToken deliveryToken)
    {
        if (!envelope.Receiver.HasValue)
        {
            throw new InvalidOperationException("Message must have a receiver to be sent.");
        }

        CancellationTokenSource combinedSource = CancellationTokenSource.CreateLinkedTokenSource(envelope.Cancellation, deliveryToken);
        MessageContext messageContext = new(envelope.MessageId, combinedSource.Token)
        {
            Sender = envelope.Sender,
            IsRpc = false
        };

        AgentId receiver = envelope.Receiver.Value;
        IHostableAgent agent = await this.EnsureAgentAsync(receiver);

        return await agent.OnMessageAsync(envelope.Message, messageContext);
    }

    public ValueTask<object?> SendMessageAsync(object message, AgentId recepient, AgentId? sender = null, string? messageId = null, CancellationToken cancellationToken = default)
    {
        return this.ExecuteTracedAsync(async () =>

View on GitHub (pinned to 027ecf0a37)

Solutions

  1. Set the receiver before enqueueing: build the envelope with .WithReceiver(agentId) (or use ForSend rather than ForPublish).
  2. Prefer the public SendMessageAsync(agent, message) API, which sets the receiver for you, instead of hand-building envelopes.
  3. Audit custom MessageEnvelope construction sites for missing WithReceiver calls.

Example fix

// before
MessageDelivery delivery = new MessageEnvelope(message, messageId, ct)
    .WithSender(sender)
    .ForPublish(topic, this.PublishMessageServicer);
await delivery.Future; // routed to SendMessageServicer without a receiver

// after
MessageDelivery delivery = new MessageEnvelope(message, messageId, ct)
    .WithSender(sender)
    .ForSend(receiver, this.SendMessageServicer);
await delivery.Future;
Defensive patterns

Strategy: validation

Validate before calling

if (envelope.Receiver is not { } target)
{
    throw new InvalidOperationException("Cannot send: envelope has no receiver.");
}
await runtime.SendMessageAsync(target, envelope.Message);

Type guard

static bool HasReceiver(MessageEnvelope envelope) => envelope.Receiver.HasValue;

Try / catch

try { await runtime.SendMessageAsync(agentId, message); }
catch (InvalidOperationException ex) when (ex.Message.Contains("receiver")) { /* fix envelope construction; do not retry */ }

Prevention

When it happens

Trigger: Enqueuing a MessageEnvelope that was built with ForPublish (which sets a topic, not a receiver) but serviced through the send path; constructing a MessageEnvelope manually and forgetting .WithReceiver(agentId); calling AgentProxy methods where the proxy was created from an envelope without a receiver. The check at InProcessRuntime.cs:106 is `if (!envelope.Receiver.HasValue)`.

Common situations: Mixing the publish API (PublishMessageAsync + ForPublish) with the send servicer; copy-pasting envelope-building code from a publish flow into a send flow; a custom MessageDelivery pipeline dropping the receiver assignment.

Related errors


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