Skip to content

fix(react): use the latest transport in useChat instead of a stale one#16546

Merged
n1ckoates merged 5 commits into
mainfrom
nick/usechat-stale-transport
Jul 1, 2026
Merged

fix(react): use the latest transport in useChat instead of a stale one#16546
n1ckoates merged 5 commits into
mainfrom
nick/usechat-stale-transport

Conversation

@n1ckoates

@n1ckoates n1ckoates commented Jul 1, 2026

Copy link
Copy Markdown
Member

Background

useChat() creates its Chat instance once and stores it in a useRef(), so as a result, a transport passed to useChat() was captured and then frozen at its value in the first render. If react state later changes, the transport becomes stale.

A very similar problem was addressed in #8985 but with callbacks.

Summary

Rather than passing the transport directly to Chat, this passes a proxy object that always reads the latest transport (or falls back to a default one).

This uses the same solution as in #8985 for callbacks.

Manual Verification

Added a route to the ai-e2e-next example at /chat/stale-transport-demo. It reproduces the bug without the changes made, and then is fixed with these changes.

Checklist

  • All commits are signed (PRs with unsigned commits cannot be merged)
  • Tests have been added / updated (for bug fixes / features)
  • Documentation has been added / updated (for bug fixes / features)
  • A patch changeset for relevant packages has been added (for bug fixes / features - run pnpm changeset in the project root)
  • I have reviewed this pull request (self-review)

Related Issues

Fixes #7819

Closes #12330
Closes #13464
Closes #15380
Closes #16326

@n1ckoates n1ckoates marked this pull request as ready for review July 1, 2026 18:25
@n1ckoates n1ckoates merged commit 8b2dc3c into main Jul 1, 2026
49 checks passed
@n1ckoates n1ckoates deleted the nick/usechat-stale-transport branch July 1, 2026 18:30
gr2m added a commit that referenced this pull request Jul 6, 2026
…tale one (#16806)

Backport of #16546 to `release-v6.0`. `useChat()` creates its `Chat`
instance once in a `useRef`, so a `transport` passed to `useChat()` was
frozen at its first-render value and became stale after React state
changes; the fix extends the existing latest-values ref pattern (already
used for callbacks on v6) to also cover the transport, handing `Chat` a
stable proxy transport whose `sendMessages`/`reconnectToStream` always
delegate to the latest transport (falling back to a lazily created
`DefaultChatTransport`). The `use-chat.ts` rewrite from `callbacksRef`
to `latestRef` applied cleanly and matches main exactly, except that
v6's `shouldRecreateChat` guard is kept as-is (the nullish-id guard from
#16484 is backported independently in its own PR); conflict resolution
was limited to the import block (v6 does not import `fireEvent` in the
test file) and re-indenting the new `stale transport` test describe
block to v6's flat test file structure (main wraps tests in an outer
`describe('use-chat')`). Verified the ported regression test fails on v6
without the fix and passes with it. Part of the v6.0 backport tracking
issue #16767.

Co-authored-by: Nick Oates <nick.oates@vercel.com>
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.

In useChat in @ai-sdk/react, state sent via transport#body is always stale

2 participants