Skip to content

Conversation

@jacobwisniewski
Copy link

Summary

Fixes #9610

This PR adds a ref guard to prevent resumeStream() from being called twice when React StrictMode double-invokes effects during development.

Problem

When using useChat with resume: true, refreshing the page mid-stream causes duplicate stream requests because React StrictMode runs effects twice (mount → unmount → mount). The current implementation has no protection against this:

useEffect(() => {
  if (resume) {
    chatRef.current.resumeStream();
  }
}, [resume, chatRef]);

This leads to:

  • Duplicated/repeated text in the UI
  • Multiple concurrent stream consumers
  • Inconsistent message state
  • onData callbacks being called twice per server write

Solution

Add a hasResumedRef that tracks whether resume has already been attempted:

const hasResumedRef = useRef(false);

useEffect(() => {
  if (resume && !hasResumedRef.current) {
    hasResumedRef.current = true;
    chatRef.current.resumeStream();
  }
}, [resume, chatRef]);

Testing

Added a test case that renders the component in <React.StrictMode> and verifies only one resume request is made despite effects running twice.

Checklist

  • Code changes
  • Test case added
  • Follows existing code style

@vercel-ai-sdk vercel-ai-sdk bot added the ai/ui label Jan 4, 2026
@jacobwisniewski jacobwisniewski force-pushed the fix/use-chat-strict-mode-resume branch from 9925e67 to 763f0a4 Compare January 4, 2026 10:54
Add a ref guard to prevent resumeStream() from being called twice
when React StrictMode double-invokes effects during development.

This fixes an issue where refreshing the page mid-stream would cause
duplicate stream requests, leading to:
- Duplicated/repeated text in the UI
- Multiple concurrent stream consumers
- Inconsistent message state

The fix adds a hasResumedRef that tracks whether resume has already
been attempted, preventing the second invocation from making another
request.

Fixes vercel#9610
@jacobwisniewski jacobwisniewski force-pushed the fix/use-chat-strict-mode-resume branch from 763f0a4 to 7e31534 Compare January 5, 2026 00:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

onData callback called twice per writer.write() when using resumable streams

1 participant