fix: handle tuples in deepcopy_minimal to prevent mutation of user data#1213
Open
roli-lpci wants to merge 1 commit intoanthropics:mainfrom
Open
fix: handle tuples in deepcopy_minimal to prevent mutation of user data#1213roli-lpci wants to merge 1 commit intoanthropics:mainfrom
deepcopy_minimal to prevent mutation of user data#1213roli-lpci wants to merge 1 commit intoanthropics:mainfrom
Conversation
…tion `deepcopy_minimal` copies `dict` and `list` but skips `tuple`, returning it as-is. When `files.beta.upload()` is called with a `FileTypes` tuple containing a headers dict, the tuple passes through uncopied. httpx then mutates the user's original headers dict by injecting `Content-Type` during multipart encoding, permanently contaminating user data. This adds tuple handling to `deepcopy_minimal`, matching the existing pattern for dicts and lists. Tuples are recursively copied so that mutable elements (like headers dicts) get independent copies. Note: `_utils/_utils.py` has no Stainless codegen header, consistent with hand-maintained utility code. If this change should be applied to the generation template instead, happy to redirect. Fixes anthropics#1202 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
deepcopy_minimalcopiesdictandlistbut intentionally skipstuple(returning it as-is). Whenfiles.beta.upload()is called with a 4-elementFileTypestuple containing a headers dict, the tuple passes through uncopied. httpx then mutates the user's original headers dict by injectingContent-Typeduring multipart encoding.Users who reuse file tuples across multiple uploads see their headers silently contaminated.
Changes
src/anthropic/_utils/_utils.py— Add tuple handling todeepcopy_minimal, matching the existing pattern for dicts and lists. Tuples are recursively copied so mutable elements (like headers dicts) get independent copies.tests/test_deepcopy.py— Replace the old assertion that tuples pass through uncopied (assert obj3 is obj4) with 4 new tests covering: simple tuples, tuples with mutable contents (the bug scenario), dicts containing tuples (files.beta.uploadpattern), and lists of tuples (skills/versionspattern).Note on behavioral change: The previous test explicitly asserted tuples are NOT copied. This was a deliberate scope limitation of
deepcopy_minimalthat did not anticipate the httpx mutation path. This PR intentionally reverses that — tuples are now recursively copied like dicts and lists.Note on Stainless:
_utils/_utils.pyhas no codegen header, consistent with hand-maintained utility code. If this change should be applied to the generation template instead, happy to redirect.Testing
Fixes #1202