microsoft/autogen · error · ArgumentException

Role mismatch

Error message

Role mismatch

What it means

TextMessage.Update(TextMessageUpdate) is used to append streaming deltas onto an existing message, and requires update.Role to equal the message's current Role; otherwise it throws ArgumentException('Role mismatch', paramName: update). This guards incremental streaming state from being corrupted by a chunk that belongs to a different role (e.g. system vs assistant).

Source

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

    public TextMessage(Role role, string content, string? from = null)
    {
        this.Content = content;
        this.Role = role;
        this.From = from;
    }

    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()
    {

View on GitHub (pinned to 027ecf0a37)

Solutions

  1. Only call Update with chunks whose Role matches the message created from the first chunk.
  2. Start a new TextMessage when the role changes instead of updating the existing one.
  3. Set Role explicitly when constructing each TextMessageUpdate rather than relying on defaults.
  4. When merging streams, key messages by (From, Role) so chunks route to the right accumulator.

Example fix

// before
var msg = new TextMessage(update1); // Role.Assistant
msg.Update(update2); // update2.Role == Role.System -> throws

// after
if (update2.Role != msg.Role)
{
    msg = new TextMessage(update2); // start a new message for the new role
}
else
{
    msg.Update(update2);
}
Defensive patterns

Strategy: validation

Validate before calling

if (update.Role != msg.Role)
    msg = new TextMessage(update); // start a new message instead of updating
else
    msg.Update(update);

Type guard

static bool IsSameRole(TextMessage msg, TextMessageUpdate update) => update.Role == msg.Role;

Try / catch

try { msg.Update(update); }
catch (ArgumentException ex) when (ex.Message.Contains("Role mismatch"))
{
    msg = new TextMessage(update); // role changed: begin a new message
}

Prevention

When it happens

Trigger: Streaming updates where the first chunk is Role.Assistant and a later chunk is Role.System (or Function); constructing TextMessageUpdate with a default/unset Role; merging chunks from two different streams into one message.

Common situations: Custom streaming pipelines that forward every delta regardless of role; deserializing update events where the role field is missing and defaults differently; mixing system-prompt injection events into the assistant token stream.

Related errors


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