Skip to content

fix: shallow copy content_block in BetaMessageStream#accumulateMessage#938

Open
MaxwellCalkin wants to merge 1 commit intoanthropics:mainfrom
MaxwellCalkin:fix/beta-stream-missing-content-block-copy
Open

fix: shallow copy content_block in BetaMessageStream#accumulateMessage#938
MaxwellCalkin wants to merge 1 commit intoanthropics:mainfrom
MaxwellCalkin:fix/beta-stream-missing-content-block-copy

Conversation

@MaxwellCalkin
Copy link

Summary

  • Fix missing defensive copy in BetaMessageStream: The content_block_start case in BetaMessageStream#accumulateMessage pushes event.content_block directly into the snapshot's content array, while the non-beta MessageStream correctly uses { ...event.content_block } to create a shallow copy.

Details

In src/lib/MessageStream.ts (line 600):

case 'content_block_start':
    snapshot.content.push({ ...event.content_block }); // ✅ shallow copy
    return snapshot;

In src/lib/BetaMessageStream.ts (line 606, before this fix):

case 'content_block_start':
    snapshot.content.push(event.content_block); // ❌ direct reference
    return snapshot;

Without the copy, the snapshot holds a direct reference to the event object. Any external code that retains and mutates the original event's content_block would inadvertently corrupt the accumulated message snapshot. The rest of the content_block_delta handling in both files already creates new objects via spread ({ ...snapshotContent, ... }), so this is specifically a gap in the content_block_start case of the beta stream.

This is a one-character fix ({ ...event.content_block } instead of event.content_block) that aligns BetaMessageStream with the existing MessageStream behavior.

Test plan

  • Verify existing tests pass
  • The fix is a minimal change that matches the pattern already used in MessageStream
  • All subsequent content_block_delta handlers already create new objects via spread, so this only affects the initial content block reference

🤖 Generated with Claude Code

…Stream

In BetaMessageStream#accumulateMessage, the content_block_start case
pushes event.content_block directly into the snapshot's content array
without copying it. This is inconsistent with MessageStream, which
correctly uses { ...event.content_block } to create a shallow copy.

Without the copy, the snapshot holds a direct reference to the event
object. Any external code that retains and mutates the original event's
content_block would inadvertently corrupt the accumulated message
snapshot. The non-beta MessageStream already guards against this by
creating a shallow copy.

This aligns BetaMessageStream with the existing MessageStream behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@MaxwellCalkin MaxwellCalkin requested a review from a team as a code owner March 8, 2026 21:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant