microsoft/autogen · error · ArgumentException

From mismatch

Error message

From mismatch

What it means

TextMessage.Update(TextMessageUpdate) also requires update.From to equal the message's current From; a mismatch throws ArgumentException('From mismatch', paramName: update). It ensures streamed chunks all originate from the same agent so attribution cannot silently change mid-stream. Note From is nullable: null == null passes, but null vs "agent" fails.

Source

Thrown at dotnet/src/AutoGen.Core/Message/TextMessage.cs:31

    }

    public TextMessage(TextMessageUpdate update)
    {
        this.Content = update.Content ?? string.Empty;
        this.Role = update.Role;
        this.From = update.From;
    }

    public void Update(TextMessageUpdate update)
    {
        if (update.Role != this.Role)
        {
            throw new System.ArgumentException("Role mismatch", nameof(update));
        }

        if (update.From != this.From)
        {
            throw new System.ArgumentException("From mismatch", nameof(update));
        }

        this.Content = this.Content + update.Content ?? string.Empty;
    }

    public Role Role { get; set; }

    public string Content { get; set; }

    public string? From { get; set; }

    public override string ToString()
    {
        return $"TextMessage({this.Role}, {this.Content}, {this.From})";
    }

    public string? GetContent()
    {

View on GitHub (pinned to 027ecf0a37)

Solutions

  1. Set From consistently (either always null or always the agent name) on the seed message and every update.
  2. Initialize the accumulator from the first update including its From rather than from a bare completion.
  3. Key accumulators by From (and Role) so chunks from different senders never meet in one Update call.
  4. Normalize before updating: if msg.From is null and update.From is set, recreate the message with the update's From.

Example fix

// before
var msg = new TextMessage(Role.Assistant, "", from: null);
msg.Update(new TextMessageUpdate(Role.Assistant, "delta") { From = "assistant" }); // throws

// after
var msg = new TextMessage(Role.Assistant, "", from: "assistant");
msg.Update(new TextMessageUpdate(Role.Assistant, "delta") { From = "assistant" });
Defensive patterns

Strategy: validation

Validate before calling

if (update.From != msg.From)
{
    if (msg.From is null && msg.Content.Length == 0) msg = new TextMessage(update);
    else throw new StreamingException($"Chunk From '{update.From}' != message From '{msg.From}'");
}
else msg.Update(update);

Type guard

static bool IsSameSender(TextMessage msg, TextMessageUpdate update) => update.From == msg.From;

Try / catch

try { msg.Update(update); }
catch (ArgumentException ex) when (ex.Message.Contains("From mismatch"))
{
    // route chunk to the accumulator keyed by update.From instead
}

Prevention

When it happens

Trigger: First chunk has From = null (created via new TextMessage(update) where update.From was null) and later chunks carry From = "assistant"; interleaving chunks from two agents into one accumulator; middleware that sets From on outgoing chunks but not the initial one.

Common situations: Streaming middleware that enriches messages with From after creation; constructing the seed TextMessage from a raw completion (no From) and applying updates from agent-tagged events; concurrent agents writing into a shared streaming buffer.

Related errors


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