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
- Only call Update with chunks whose Role matches the message created from the first chunk.
- Start a new TextMessage when the role changes instead of updating the existing one.
- Set Role explicitly when constructing each TextMessageUpdate rather than relying on defaults.
- 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
- Key streaming accumulators by (From, Role) so chunks never cross roles.
- Always set Role explicitly on TextMessageUpdate instances.
- Treat a role change mid-stream as a new message, never an update.
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
- From mismatch
- The from property of the message {message} is different from
- Invalid DataUri format, expected data:[<mediatype>][;base64]
- Data cannot be empty
- Invalid aggregate message {reason}
AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15).
Data as JSON: /api/errors/817d4f630134cb82.
Report an issue: GitHub.