Skip to content

Fix shared mutable state in chat options builder clone()#6498

Open
subhashpolisetti wants to merge 1 commit into
spring-projects:mainfrom
subhashpolisetti:clone-defensive-copy-sweep
Open

Fix shared mutable state in chat options builder clone()#6498
subhashpolisetti wants to merge 1 commit into
spring-projects:mainfrom
subhashpolisetti:clone-defensive-copy-sweep

Conversation

@subhashpolisetti

Copy link
Copy Markdown
Contributor

The builder clone() methods in several ChatOptions implementations copied mutable collection fields by reference instead of creating independent copies. A builder obtained via clone() therefore shared those collections with its source, so mutating one affected the other.

This mirrors the fix applied to AnthropicChatOptions in #6487 and aligns each clone() with the defensive copying these builders already perform in combineWith(), and that the base ChatOptions builder (stopSequences) and the tool-calling builder (toolCallbacks, toolContext) already perform in their own clone().

Affected builders:

  • BedrockChatOptionsrequestParameters
  • DeepSeekChatOptionstools
  • GoogleGenAiChatOptionssafetySettings, labels
  • MistralAiChatOptionstools
  • OpenAiChatOptionscustomHeaders, logitBias, outputModalities, metadata, and the previously uncopied extraBody

Testing:

Added regression tests for each builder that explicitly fail on the previous aliasing behavior.

Added null-safety tests for each modified clone() method.

Note: I am happy to split this into per-module PRs if you would prefer separate reviews.

See #6487

The builder clone() methods in several ChatOptions implementations
copied mutable collection fields by reference instead of creating
independent copies, so a builder obtained via clone() shared those
collections with its source and mutating one affected the other.

This mirrors the fix applied to AnthropicChatOptions in spring-projects#6487 and aligns
each clone() with the defensive copying these builders already perform in
combineWith() and that the base ChatOptions and tool-calling builders
already perform in their own clone(). Affected builders: BedrockChatOptions
(requestParameters), DeepSeekChatOptions (tools), GoogleGenAiChatOptions
(safetySettings, labels), MistralAiChatOptions (tools), and OpenAiChatOptions
(customHeaders, logitBias, outputModalities, metadata, and the previously
uncopied extraBody).

See spring-projects#6487

Signed-off-by: subhash polisetti <subhashr161347@gmail.com>
@sdeleuze sdeleuze self-assigned this Jun 23, 2026
@sdeleuze sdeleuze added this to the 2.0.1 milestone Jun 23, 2026
@sdeleuze sdeleuze added bug Something isn't working options and removed status: waiting-for-triage labels Jun 23, 2026
@ericbottard

Copy link
Copy Markdown
Member

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working options

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants