Description
Passing id: undefined to useChat causes the internal Chat instance, and therefore all messages and stream state, to be recreated on every render. Sent messages and in-flight streams disappear immediately, so the UI never shows a response.
This is easy to hit because id={conversationId ?? undefined} is a common pattern. The surprising part is that passing id: undefined behaves very differently from omitting id, even though the two are usually equivalent.
Versions
@ai-sdk/react@3.0.209
ai@6.0.207
Root cause
In the useChat hook (packages/react/src/use-chat.ts):
const shouldRecreateChat =
("chat" in options && options.chat !== chatRef.current) ||
("id" in options && chatRef.current.id !== options.id);
if (shouldRecreateChat) {
chatRef.current = "chat" in options ? options.chat : new Chat(optionsWithCallbacks);
}
When id: undefined is passed:
"id" in options is true, since the key exists even though its value is undefined.
- The
Chat constructor defaults id to generateId(), so chatRef.current.id is an auto-generated UUID.
- As a result,
chatRef.current.id !== options.id evaluates to uuid !== undefined, which is always true.
So shouldRecreateChat stays true and a fresh Chat with empty messages is created on every render.
Reproduction
function Chat({ conversationId }: { conversationId?: string }) {
// conversationId is undefined for a brand-new chat
const { messages, sendMessage } = useChat({ id: conversationId ?? undefined });
// Send a message. It briefly appears, then vanishes on the next render,
// and the streamed assistant response never shows.
return <button onClick={() => sendMessage({ text: 'hi' })}>send</button>;
}
Expected behavior
id: undefined should behave the same as omitting id, keeping the auto-generated stable id instead of recreating the chat on every render.
Suggested fix
Guard against a nullish id:
("id" in options && options.id != null && chatRef.current.id !== options.id)
Workaround
Provide a stable fallback id:
const fallbackId = useRef(crypto.randomUUID());
const { messages } = useChat({ id: conversationId ?? fallbackId.current });
Description
Passing
id: undefinedtouseChatcauses the internalChatinstance, and therefore all messages and stream state, to be recreated on every render. Sent messages and in-flight streams disappear immediately, so the UI never shows a response.This is easy to hit because
id={conversationId ?? undefined}is a common pattern. The surprising part is that passingid: undefinedbehaves very differently from omittingid, even though the two are usually equivalent.Versions
@ai-sdk/react@3.0.209ai@6.0.207Root cause
In the
useChathook (packages/react/src/use-chat.ts):When
id: undefinedis passed:"id" in optionsistrue, since the key exists even though its value isundefined.Chatconstructor defaultsidtogenerateId(), sochatRef.current.idis an auto-generated UUID.chatRef.current.id !== options.idevaluates touuid !== undefined, which is alwaystrue.So
shouldRecreateChatstaystrueand a freshChatwith empty messages is created on every render.Reproduction
Expected behavior
id: undefinedshould behave the same as omittingid, keeping the auto-generated stable id instead of recreating the chat on every render.Suggested fix
Guard against a nullish
id:Workaround
Provide a stable fallback id: