Fix InvalidOperationException in CoalesceWebSearchToolCallContent#7419
Merged
stephentoub merged 3 commits intodotnet:mainfrom Mar 20, 2026
Merged
Conversation
CoalesceWebSearchToolCallContent merged streaming updates by mutating the original content objects in-place. In particular, the direct assignment existing.Queries = webSearchCall.Queries made two objects share the same Queries list. This is a problem because ToChatResponse can be called multiple times on the same streaming updates: FunctionInvokingChatClient calls it internally to process function calls, and the caller (e.g. ChatClientAgent from the Agents Framework) calls it again on the same collected updates. On the second call, both content objects have non-null Queries pointing to the same list, so the foreach-merge path tries to iterate and add to the same list simultaneously, throwing InvalidOperationException. The fix creates a new WebSearchToolCallContent with the merged data instead of mutating the originals, matching the pattern used by all the other coalescing methods. This makes ToChatResponse safe to call multiple times on the same updates. Fixes dotnet#7414 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes an InvalidOperationException thrown when ToChatResponse is invoked multiple times over the same streaming updates containing WebSearchToolCallContent, by avoiding in-place mutation during coalescing.
Changes:
- Update
CoalesceWebSearchToolCallContentto create a new mergedWebSearchToolCallContentinstead of mutating existing instances. - Add a regression test that calls
ToChatResponsetwice on the same update sequence (sync/async), covering both “first update has queries” and “first update has null queries” paths.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/Libraries/Microsoft.Extensions.AI.Abstractions/ChatCompletion/ChatResponseExtensions.cs | Changes web-search coalescing to be non-mutating by replacing the coalesced item with a newly constructed merged instance. |
| test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/ChatCompletion/ChatResponseUpdateExtensionsTests.cs | Adds a regression test reproducing the multi-ToChatResponse scenario that previously caused the exception. |
The old mutating code preserved the first item's Annotations implicitly. The new code creates a fresh object, so Annotations must be explicitly carried over. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jozkee
approved these changes
Mar 20, 2026
jozkee
reviewed
Mar 20, 2026
jozkee
reviewed
Mar 20, 2026
Co-authored-by: David Cantú <dacantu@microsoft.com>
jozkee
pushed a commit
to jozkee/extensions
that referenced
this pull request
Apr 3, 2026
…tnet#7419) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix InvalidOperationException in CoalesceWebSearchToolCallContent
Fixes #7414
Problem
CoalesceWebSearchToolCallContentmerged streaming updates by mutating the original content objects in-place. In particular,existing.Queries = webSearchCall.Queriesmade two objects share the sameQuerieslist instance. This is a problem becauseToChatResponsecan be called multiple times on the same streaming updates:FunctionInvokingChatClientcalls it internally to process function calls (line 666), and the caller (e.g.ChatClientAgentfrom the Agents Framework) calls it again on the same collected updates. On the second call, both content objects now have non-nullQueriespointing to the same list, so the foreach-merge path tries to iterate and add to the same list simultaneously, throwingInvalidOperationException: Collection was modified; enumeration operation may not execute.Fix
Create a new
WebSearchToolCallContentwith the merged data instead of mutating the originals. This matches the pattern used by all the other coalescing methods (Coalesce<T>forTextContent,CodeInterpreterToolCallContent, etc.), which create new objects via factory delegates. WhenexistingandwebSearchCallare the same object instance (a degenerate case), the duplicate is simply removed without creating a new object.Tests
Added a regression test that mirrors the real-world scenario: streaming updates with an in-progress web search (null Queries), a done web search (populated Queries), and a function call, with
ToChatResponsecalled twice on the same updates. Parameterized over sync/async and whether the first item has queries (exercising both the reference-assignment and list-combining branches).Microsoft Reviewers: Open in CodeFlow