microsoft/autogen · error · InvalidOperationException

The recent update is not a TextMessage

Error message

The recent update is not a TextMessage

What it means

Thrown by PrintMessageMiddleware while relaying a streaming reply. The middleware folds streaming chunks into one accumulated message; when a TextMessageUpdate arrives and the message accumulated so far (recentUpdate) is not null and not a TextMessage, it cannot append text to it (e.g. a ToolCallMessage was accumulated first) and throws InvalidOperationException.

Source

Thrown at dotnet/src/AutoGen.Core/Middleware/PrintMessageMiddleware.cs:77

                {
                    // Print from: xxx
                    Console.WriteLine($"from: {textMessageUpdate.From}");
                    recentUpdate = new TextMessage(textMessageUpdate);
                    Console.Write(textMessageUpdate.Content);

                    yield return message;
                }
                else if (recentUpdate is TextMessage recentTextMessage)
                {
                    // Print the content of the message
                    Console.Write(textMessageUpdate.Content);
                    recentTextMessage.Update(textMessageUpdate);

                    yield return recentTextMessage;
                }
                else
                {
                    throw new InvalidOperationException("The recent update is not a TextMessage");
                }
            }
            else if (message is ToolCallMessageUpdate toolCallUpdate)
            {
                if (recentUpdate is null)
                {
                    recentUpdate = new ToolCallMessage(toolCallUpdate);

                    yield return message;
                }
                else if (recentUpdate is ToolCallMessage recentToolCallMessage)
                {
                    recentToolCallMessage.Update(toolCallUpdate);

                    yield return message;
                }
                else
                {

View on GitHub (pinned to 027ecf0a37)

Solutions

  1. Fix the streaming agent so one stream contains only one kind of update (all TextMessageUpdate or all ToolCallMessageUpdate), not interleaved types
  2. If you control the agent, start the stream with the text updates before emitting any complete non-text IMessage
  3. Remove or reorder PrintMessageMiddleware in the agent's middleware chain if you must interleave heterogeneous messages
  4. Catch InvalidOperationException around the streaming enumeration only as a last resort, since the console printout will already be partially written

Example fix

// before: agent yields ToolCallMessageUpdate, then TextMessageUpdate in the same stream
// after: yield text updates first, or split into separate replies
await foreach (var update in textUpdates) yield return update; // only TextMessageUpdate in this stream
Defensive patterns

Strategy: validation

Validate before calling

// Before consuming a stream through PrintMessageMiddleware, verify homogeneous update types
var types = new HashSet<Type>();
await foreach (var m in agent.GenerateStreamingReplyAsync(msgs, ct)) types.Add(m.GetType());
if (types.Count > 1 && types.Contains(typeof(TextMessageUpdate)))
    throw new InvalidOperationException("Stream mixes text updates with other message types");

Type guard

static bool IsTextUpdateStream(IEnumerable<IMessage> replayed) =>
    replayed.All(m => m is TextMessageUpdate or TextMessage);

Try / catch

try { await foreach (var m in printingAgent.GenerateStreamingReplyAsync(msgs, ct)) { /* ... */ } }
catch (InvalidOperationException e) when (e.Message.Contains("not a TextMessage"))
{ /* fall back to non-streaming call */ }

Prevention

When it happens

Trigger: An IStreamingAgent's GenerateStreamingReplyAsync yields a ToolCallMessageUpdate (or any non-text IMessage) first, then yields a TextMessageUpdate afterwards; the middleware's else branch at PrintMessageMiddleware.cs:77 fires because recentUpdate is a ToolCallMessage, not a TextMessage.

Common situations: Agents that emit tool-call chunks followed by text chunks in the same stream, custom agents mixing update types in one streaming response, or middleware pipelines that inject intermediate non-update messages before text deltas.

Related errors


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