TanStack AI version
@tanstack/ai-react v0.23.0 (@tanstack/ai-client v0.30.0; verified unchanged in v0.31.0 and main)
Framework/Library version
React v19
Describe the bug and the steps to reproduce it
What happens
I'm using persistence: true, so the client loads an existing thread from my server when the chat mounts. When that load fails (my server returned a 500), the failure is invisible: onError doesn't fire, chat.error stays undefined, and the client reports status: 'ready' with zero messages, exactly what it reports for a thread that's genuinely empty. So my app can't tell "this thread failed to load" from "this thread has no messages", and the user is stuck on an empty/loading screen. There's no retry either; the load happens once on mount.
Steps to reproduce
No provider/API key needed, the failure happens before any send:
const chat = useChat({
connection: fetchServerSentEvents('/nonexistent-endpoint'), // hydrate GET fails
persistence: true,
threadId: 'thread-1',
onError: (e) => console.log('onError', e), // never logs
})
// Render chat.status + chat.error: status stays 'ready', error stays undefined,
// while the Network tab shows the failed GET.
What I expected
An error signal. GenerationClient.failHydration handles this exact case (status: 'error' + onError) with the comment "so a broken server is distinguishable from an empty one and the app can retry."
Cause
hydrateFromServer in chat-client.ts:
try {
result = await hydrate(this.threadId)
} catch {
return
}
No callback, state change, event, or retry is reachable from that catch. Same in 0.30.0, 0.31.0, and main.
Related breakage
For apps where users supply their own provider key (BYOK), a 401 during hydrate throws ByokMissingError into this same catch, so the key-request flow never triggers on thread load. The send path special-cases that error; the hydrate path eats it.
Fix
Minimal: catch (error) { this.callbacksRef.current.onError(error) }.
Fuller: port the failHydration pattern so state reflects it too.
(#1120 asks for hydration state generally, this may want to fold into that.)
Happy to PR either. Which shape do you prefer?
Your Minimal, Reproducible Example - (Sandbox Highly Recommended)
https://codesandbox.io/p/sandbox/pvgmmh?file=%2Findex.js
Screenshots or Videos (Optional)
No response
Do you intend to try to help solve this bug with your own PR?
Yes, I think I know how to fix it and will discuss it in the comments of this issue
Terms & Code of Conduct
TanStack AI version
@tanstack/ai-react v0.23.0 (@tanstack/ai-client v0.30.0; verified unchanged in v0.31.0 and main)
Framework/Library version
React v19
Describe the bug and the steps to reproduce it
What happens
I'm using
persistence: true, so the client loads an existing thread from my server when the chat mounts. When that load fails (my server returned a 500), the failure is invisible:onErrordoesn't fire,chat.errorstays undefined, and the client reportsstatus: 'ready'with zero messages, exactly what it reports for a thread that's genuinely empty. So my app can't tell "this thread failed to load" from "this thread has no messages", and the user is stuck on an empty/loading screen. There's no retry either; the load happens once on mount.Steps to reproduce
No provider/API key needed, the failure happens before any send:
What I expected
An error signal.
GenerationClient.failHydrationhandles this exact case (status: 'error'+onError) with the comment "so a broken server is distinguishable from an empty one and the app can retry."Cause
hydrateFromServerin chat-client.ts:No callback, state change, event, or retry is reachable from that catch. Same in 0.30.0, 0.31.0, and main.
Related breakage
For apps where users supply their own provider key (BYOK), a 401 during hydrate throws
ByokMissingErrorinto this same catch, so the key-request flow never triggers on thread load. The send path special-cases that error; the hydrate path eats it.Fix
Minimal:
catch (error) { this.callbacksRef.current.onError(error) }.Fuller: port the
failHydrationpattern so state reflects it too.(#1120 asks for hydration state generally, this may want to fold into that.)
Happy to PR either. Which shape do you prefer?
Your Minimal, Reproducible Example - (Sandbox Highly Recommended)
https://codesandbox.io/p/sandbox/pvgmmh?file=%2Findex.js
Screenshots or Videos (Optional)
No response
Do you intend to try to help solve this bug with your own PR?
Yes, I think I know how to fix it and will discuss it in the comments of this issue
Terms & Code of Conduct